以下片段compiles与Clang 4.0没有错误,但GCC 7.0产生errors(注意使用-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);
}
具体来说,GCC抱怨lambda和嵌套类的方法都没有链接,所以它们不能用作非类型模板参数 .
至少对于lambda案例,我认为Clang是正确的(并且GCC是错误的)因为(引自cppreference,转换运算符):
此转换函数返回的值是指向具有C语言链接的函数的指针,该函数在调用时具有与直接调用闭包对象的函数调用操作符相同的效果 .
海湾合作委员会是否行为不端?
2 回答
根据http://en.cppreference.com/w/cpp/language/template_parameters#Non-type_template_parameter,似乎外部联系不再是自C17以来的要求 . 在[temp.arg.nontype]的_1723614_下的C 17草案中找到相同的语言(注意它作为C 14草案被错误地链接) ) .
cppreference上的那个链接也特别提到了函数指针,在C17之前:
因为你的问题被标记为C 1z(我们现在应该有17个标签并且使用它而不是17完成)我们应该使用第一组规则 . 您的示例似乎不属于C 17的任何异常类别,因此gcc出错 .
请注意,如果将语言标志更改为14,则clang不会编译您的示例 .
我同意Nir's answer并希望为其添加一些信息 . 他引用了标准中的相关部分(§14.3.2[temp.arg.nontype]),该部分表明不再需要非类型参数进行链接,但这仍然没有表明GCC行为不端对于lambda部分 . 为此我们需要证明
static_cast<FUNCT>(lambda)
是一个转换的常量表达式 . 为此我们需要一个Nir链接的newer草案 . 而这一节§5.1.5Lambda表达式[expr.prim.lambda]:
有趣的是,GCC claims已经在已经发布的版本6中实现了这个(N4268)(如果你想原谅GCC _1523620尚未正式发布,那么也许什么时候它会出来,这将是固定的):
总而言之,这是GCC中的一个错误 .