`nullopt`可以作为非类型模板参数传递吗?

时间:2018-03-13 08:58:45

标签: c++ c++17

考虑以下代码示例

#include <iostream>
#include <experimental/optional>

std::experimental::optional<int> dflt(42);

template<const std::experimental::optional<int>& Dflt>
void foo() {
    if (Dflt) {
        std::cout << "default is set" << std::endl;
    } else {
        std::cout << "default is not set" << std::endl;
    }
}

int main() {
        foo<dflt>();                       // <-- OK
        foo<std::experimental::nullopt>(); // <-- NOT OK
}

我想要实现的是将nullopt作为非类型函数模板参数传递,但它不会编译。它适用于具有静态存储的全局变量dflt

编译器错误消息如下所示:

foo.cc: In function ‘int main()’:
foo.cc:13:34: error: no matching function for call to ‘foo()’
  foo<std::experimental::nullopt>();
                                  ^
foo.cc:7:6: note: candidate: template<const std::experimental::fundamentals_v1::optional<int>& Dflt> void foo()
 void foo() {
      ^
foo.cc:7:6: note:   template argument deduction/substitution failed:
foo.cc:13:34: error: could not convert template argument ‘std::experimental::fundamentals_v1::nullopt’ to ‘const std::experimental::fundamentals_v1::optional<int>&’
  foo<std::experimental::nullopt>();

我知道这个例子很愚蠢,但我的主要问题是,nullopt可以作为非类型模板参数传递吗?

2 个答案:

答案 0 :(得分:6)

不是你尝试传递它的方式。

更长的答案与模板参数的约束有关。您的模板参数是引用类型。相应的论据必须满足[temp.arg.nontype]/2中的要求(强调我的):

  

非类型模板参数的模板参数应为a   转换模板参数类型的常量表达式。   对于引用或指针类型的非类型模板参数,   常量表达式的值不应指(或指针   类型,不应是地址:

     
      
  • 一个子对象,
  •   
  • 临时对象
  •   
  • 字符串文字,
  •   
  • typeid表达式的结果,或
  •   
  • 预定义的 func__变量。
  •   

nulloptnullopt_t类型的常量。这显然不是optional<int>。因此,要绑定该const引用,我们需要实现一个临时的。但这明确地使程序格式错误,正如粗体文本所示。

但请注意,您可以将参数作为对nullopt_t的引用。然后你可以传递nullopt作为参数。虽然这种模板的效用有限,但我会说。

答案 1 :(得分:3)

编辑:非类型模板参数的含量非常有限。基本上是整数/枚举或指针/指向成员/引用的指针。

Story Teller的回答解释了为什么。修复是创建一个正确类型的命名常量:

#include <iostream>
#include <experimental/optional>

std::experimental::optional<int> dflt(42);
std::experimental::optional<int> nothing(nullopt);

template<const std::experimental::optional<int>& Dflt>
void foo() {
    if (Dflt) {
        std::cout << "default is set" << std::endl;
    } else {
        std::cout << "default is not set" << std::endl;
    }
}

int main() {
        foo<dflt>();    // <-- OK
        foo<nothing>(); // <-- Should be fine.
}