C++ 为什么gcc在对非类型模板参数使用lambda时失败?

C++ 为什么gcc在对非类型模板参数使用lambda时失败?,c++,templates,lambda,c++17,non-type,C++,Templates,Lambda,C++17,Non Type,下面的代码段在Clang4.0中没有错误,但是GCC7.0产生了错误(注意-std=c++1z标志的使用) 使用FuncT=int(*)(双精度); 模板 内部温度(双a) { 返回函数(a); } int foo(双a) { 返回42; } void func() { 自动lambda=[](双a){返回5;}; 结构MyStruct { 静态int foo(双a){return 42;} }; 临时秘书(3); 临时秘书(3); 临时秘书(3); } 具体来说,GCC抱怨lambda和嵌套

下面的代码段在Clang4.0中没有错误,但是GCC7.0产生了错误(注意-std=c++1z标志的使用)

使用FuncT=int(*)(双精度);
模板
内部温度(双a)
{
返回函数(a);
}
int foo(双a)
{
返回42;
}
void func()
{
自动lambda=[](双a){返回5;};
结构MyStruct
{
静态int foo(双a){return 42;}
};
临时秘书(3);
临时秘书(3);
临时秘书(3);
}
具体来说,GCC抱怨lambda和嵌套类的方法都没有链接,因此它们不能用作非类型模板参数

至少对于lambda的情况,我认为Clang是正确的(GCC是错误的),因为(引用,转换操作符):

此转换函数返回的值是指向 用C++语言链接的函数,当调用时,它具有相同的功能 调用闭包对象的函数调用操作符时的效果 直接的

GCC是否行为不端?

根据,自C++17以来,似乎不再需要外部链接。在[temp.arg.nontype]下的C++17草稿中可以找到相同的语言(请注意,它被错误地链接为C++14草稿)

可与非类型模板参数一起使用的模板参数可以是模板参数类型的任何转换常量表达式

唯一的例外是引用和指针类型的非类型模板参数不能引用/作为

  • 子对象(包括非静态类成员、基子对象或数组) 元素)
  • 临时对象(包括在引用初始化期间创建的对象)
  • 字符串文字
  • typeid的结果
  • 或预定义的变量uu func_uu

在CPPULL上的链接还具体提到函数指针,PrC++ 17:

实例化具有非类型模板参数的模板时,以下限制适用:

对于函数指针,有效参数是指向具有链接的函数的指针(或计算为空指针值的常量表达式)

由于您的问题被标记为C++1z(我们现在应该有一个17标记,并且在17完成后使用它),因此我们应该使用第一组规则。您的示例似乎没有落入C++ 17的任何异常类别,因此GCC错误。 请注意,如果将语言标志更改为14,则clang不会编译您的示例。

我同意,并希望向其添加一些信息。他引用了标准中的相关章节(§14.3.2[临时参数非类型]),该章节表明不再要求非类型参数具有链接,但这仍然不能表明GCC在lambda部件中行为不当。为此,我们需要证明
static_cast(lambda)
是一个转换后的常量表达式。为此,我们需要一份与Nir相关的草案。这一节呢

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

  • 没有lambda捕获的非泛型lambda表达式的闭包类型具有到指针的转换函数 具有相同参数和返回类型的C++语言链接(7.5) 作为闭包类型的函数调用运算符。[…]转换 函数[…]是公共的,constexpr, 非虚拟、非显式、常量,并且具有非抛出异常 规格
  • 有趣的是,GCC已经在已经发布的版本6中实现了这个()了(如果你想通过说GCC 7还没有正式发布来原谅GCC的行为,那么可能在它发布的时候这会被修复):


    总之,这是GCC中的一个bug。

    相关:N4296是一个C++17草案。N4140(几乎)是C++14出版物。isocpp.org还没有纠正他们关于N4296是C++14草稿的说法吗?我想C++14的问题是闭包类型的操作符()有什么样的链接?好的,我会在有时间的时候编辑这个。因为这个问题是针对17个人的,所以答案并没有实质性的改变。
    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);
    }
    
    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