使用std :: optional失败函数模板参数

时间:2018-03-08 04:57:14

标签: c++ templates optional generic-programming

我想编写一个模板函数,使用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

我理解,当T1T2相同时,通过将第二个参数放入不可导入的上下文,例如

,这是一个技巧。
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

正如评论所示,有多种方法可以使代码编译,但没有一种方法像普通函数调用一样直观。也许还有一个问题要问,在不同类型的可选参数中编写模板函数的正确方法是什么?

2 个答案:

答案 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));
        // ...
    }
}