我想编写一个模板函数,使用std::optional
,
template<typename T1, typename T2>
void fcn(T1 v1, std::optional<T2> v2)
{
}
int main()
{
fcn(1, 1); // failed to compile
fcn(1, std::nullopt); // failed as well
}
但是,编译器无法在任何情况下推断T2
。
我理解,当T1
和T2
相同时,通过将第二个参数放入不可导入的上下文,例如
template<typename T>
void fcn(T v1,
std::enable_if<true, T>::type v2)
{
}
这样调用者可以正常调用fcn(1, 1)
。我的第一个问题是如何在不强制调用者编写fcn(v1, std::make_optional(v2))
的情况下为前一个示例实现此目的?
我的第二个问题是除了编写函数重载之外如何使用fcn
调用std::nullopt
?因为在我的用例中可能有几个可选参数,并且编写所有重载的排列都是不切实际的。
---- ---- EDIT
正如评论所示,有多种方法可以使代码编译,但没有一种方法像普通函数调用一样直观。也许还有一个问题要问,在不同类型的可选参数中编写模板函数的正确方法是什么?
答案 0 :(得分:1)
如何在不强制调用者编写fcn(v1,std :: make_optional(v2))的情况下为前一个示例实现此目的?
您可以通过将演绎部分与std::optional
的使用分开来实现。
除了编写函数重载之外,如何使用std :: nullopt调用fcn?
您可以添加一个模板化重载,它将处理所有std::nullopt
个案例。对于这个,您需要为该可选项指定模板参数。这不是问题,因为您可以更改2个模板参数的顺序。
template<typename T2, typename T1>
void fcn_impl(T1 v1, std::optional<T2> v2) {}
template<typename T2, typename T1>
void fcn(T1&& v1, T2&& v2)
{
fcn_impl(std::forward<T1>(v1),
std::make_optional(std::forward<T2>(v2)));
}
template<class T2, class T1>
void fcn(T1&& v1)
{
fcn_impl<T2>(std::forward<T1>(v1), std::nullopt);
}
int main()
{
// call the first one
fcn(1, 1);
// call std::nullopt one
fcn<short>(1);
}
答案 1 :(得分:1)
我的第一个问题是如何在不强制调用者编写fcn(v1,std :: make_optional(v2))的情况下为前一个示例实现此目的
您可以使用额外的间接(如liliscent所示),但对于std::null_opt
,您必须指定类型...
正如评论所示,有多种方法可以使代码编译,但没有一种方法像普通函数调用一样直观。也许还有一个问题要问,在不同类型的可选参数中编写模板函数的正确方法是什么?
一种简单的方法是重载:
template<typename T1, typename T2>
void fcn(T1 v1, T2 v2)
{
}
template<typename T1>
void fcn(T1 v1)
{
}
另一种方法是在函数内部检查给定类型
template<typename T1, typename T2, typename T3>
void fcn(T1 v1, T2 v2, T3 v3)
{
if constexpr (std::is_same<std::nullopt_t, T2>::value) {
// ...
}
if constexpr (std::is_same<std::nullopt_t, T3>::value) {
// ...
}
}
更复杂的方法是可变参数模板:
template<typename T1, typename ... Ts>
void fcn(T1 v1, Ts&&... args)
{
if constexpr (sizeof...(Ts) == 0) {
// ...
} else /*if constexpr (sizeof...(Ts) == 1)*/ {
auto& v2 = std::get<0>(std::tie(args));
// ...
}
}