首页 文章

使用lambda作为非类型模板参数时为什么gcc失败?

提问于
浏览
15

以下片段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 回答

  • 2

    根据http://en.cppreference.com/w/cpp/language/template_parameters#Non-type_template_parameter,似乎外部联系不再是自C17以来的要求 . 在[temp.arg.nontype]的_1723614_下的C 17草案中找到相同的语言(注意它作为C 14草案被错误地链接) ) .

    可以与非类型模板参数一起使用的模板参数可以是模板参数类型的任何转换常量表达式...唯一的例外是引用和指针类型的非类型模板参数不能引用/是子对象的地址(包括非静态类成员,基础子对象或数组元素);临时对象(包括在引用初始化期间创建的对象);字符串文字; typeid的结果;或预定义变量__func__ .

    cppreference上的那个链接也特别提到了函数指针,在C17之前:

    实例化具有非类型模板参数的模板时,以下限制适用:...对于函数的指针,有效参数是指向具有链接的函数的指针(或指定为空指针值的常量表达式) .

    因为你的问题被标记为C 1z(我们现在应该有17个标签并且使用它而不是17完成)我们应该使用第一组规则 . 您的示例似乎不属于C 17的任何异常类别,因此gcc出错 .

    请注意,如果将语言标志更改为14,则clang不会编译您的示例 .

  • 4

    我同意Nir's answer并希望为其添加一些信息 . 他引用了标准中的相关部分(§14.3.2[temp.arg.nontype]),该部分表明不再需要非类型参数进行链接,但这仍然没有表明GCC行为不端对于lambda部分 . 为此我们需要证明 static_cast<FUNCT>(lambda) 是一个转换的常量表达式 . 为此我们需要一个Nir链接的newer草案 . 而这一节

    §5.1.5Lambda表达式[expr.prim.lambda]:

    没有lambda-capture的非泛型lambda表达式的闭包类型有一个转换函数指向函数,C语言链接(7.5)具有与闭包类型的函数调用操作符相同的参数和返回类型 . [...]转换函数[...]是public,constexpr,非虚拟,非显式,const,并且具有非抛出异常规范 .

    有趣的是,GCC claims已经在已经发布的版本6中实现了这个(N4268)(如果你想原谅GCC _1523620尚未正式发布,那么也许什么时候它会出来,这将是固定的):

    Language Feature                                               Proposal  Available in GCC?  SD-6 Feature Test
    Allow constant evaluation for all non-type template arguments  N4268     6                  __cpp_nontype_template_args >= 201411
    

    总而言之,这是GCC中的一个错误 .

相关问题