考虑以下代码示例
#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
可以作为非类型模板参数传递吗?
答案 0 :(得分:6)
更长的答案与模板参数的约束有关。您的模板参数是引用类型。相应的论据必须满足[temp.arg.nontype]/2中的要求(强调我的):
非类型模板参数的模板参数应为a 转换模板参数类型的常量表达式。 对于引用或指针类型的非类型模板参数, 常量表达式的值不应指(或指针 类型,不应是地址:
- 一个子对象,
- 临时对象,
- 字符串文字,
- typeid表达式的结果,或
- 预定义的 func__变量。
nullopt
是nullopt_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.
}