dcm*_*m88 15 c++ lambda templates non-type c++17
下面的代码片段与Clang 4.0没有错误编译,但GCC 7.0会产生错误(注意使用-std = c ++ 1z标志).
using FuncT = int (*)(double);
template <FuncT FUNC>
int temp_foo(double a)
{
return FUNC(a);
}
int foo(double a)
{
return 42;
}
void func()
{
auto lambda = [](double a) { return 5; };
struct MyStruct
{
static int foo(double a) { return 42; }
};
temp_foo<foo>(3);
temp_foo<static_cast<FuncT>(lambda)>(3);
temp_foo<MyStruct::foo>(3);
}
Run Code Online (Sandbox Code Playgroud)
具体来说,GCC抱怨lambda和嵌套类的方法都没有链接,所以它们不能用作非类型模板参数.
至少对于lambda案例,我认为Clang是正确的(并且GCC是错误的)因为(引用cppreference,转换运算符):
此转换函数返回的值是指向具有C++语言链接的函数的指针,该函数在调用时具有与直接调用闭包对象的函数调用操作符相同的效果.
海湾合作委员会是否行为不端?
根据http://en.cppreference.com/w/cpp/language/template_parameters#Non-type_template_parameter,自C++17以来似乎不再需要外部链接。在http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf的 [temp.arg.nontype] 下的 C++17 草案中可以找到相同的语言(注它被错误地链接为 C++14 草案)。
可以与非类型模板参数一起使用的模板参数可以是模板参数类型的任何转换后的常量表达式...
唯一的例外是引用和指针类型的非类型模板参数不能引用/成为
- 子对象(包括非静态类成员、基子对象或数组元素);
- 临时对象(包括在引用初始化期间创建的临时对象);
- 字符串文字;
- typeid 的结果;
- 或预定义变量 __func__。
cppreference 上的链接还特别提到了 C++ 17 之前的函数指针:
实例化具有非类型模板参数的模板时,存在以下限制:
...
对于函数指针,有效参数是指向具有链接的函数的指针(或计算结果为空指针值的常量表达式)。
由于您的问题被标记为 C++1z(我们现在可能应该有一个 17 标签,并在 17 完成后使用它),我们应该使用第一组规则。您的示例似乎不属于 C++ 17 的任何异常类别,因此 gcc 出错。
请注意,如果您将语言标志更改为 14,clang 不会编译您的示例。