简体   繁体   English

clang错误:非类型模板参数是指没有链接的函数 - bug?

[英]clang error: non-type template argument refers to function that does not have linkage — bug?

I have some very simple ( C++11 ) code which the latest clang ( version 3.4 trunk 187493 ) fails to compile, but GCC compiles fine. 我有一些非常简单的( C ++ 11 )代码,最新的clang版本3.4 trunk 187493 )无法编译,但是GCC编译得很好。

The code (below) instantiates the function-template foo with the function-local type Bar and then tries to use its address as a non-type template parameter for the class-template Func : 代码(下面)使用函数本地类型 Bar实例化函数模板foo ,然后尝试将其地址用作类模板Func的非类型模板参数:

template<void(*FUNC_PTR)(void)>
struct Func {};

template<typename T> extern inline
void foo() {
    using Foo = Func<foo<T>>;
}
int main() {
    struct Bar {}; // function-local type
    foo<Bar>();
    return 0;
}

clang emits the following error: clang发出以下错误:

error : non-type template argument refers to function 'foo' that does not have linkage 错误 :非类型模板参数是指没有链接的函数'foo'

However, if I move type Bar to global scope (by taking it out of the function), then clang compiles it fine, proving the issue is with the type being function-local . 但是,如果我将类型Bar移动到全局范围(通过将其从函数中取出),则clang编译它很好,证明问题是函数本地的类型。

So is clang correct to emit this error, or does the standard not support this (in which case GCC is being too lenient by allowing it)? 那么clang是否正确发出此错误,或者标准是否不支持这种情况(在这种情况下,GCC通过允许它过于宽松)?


EDIT #1 : To be clear, this is not a duplicate of this question since the 'cannot use local types as template parameters' restriction was removed in C++11. 编辑#1:要清楚,这不是 这个问题的重复,因为在C ++ 11中删除了'不能使用本地类型作为模板参数'限制。 However , it's still unclear if there are linkage implications involved with using a local type, and whether clang is correct or not in emitting this error. 但是 ,仍然不清楚使用本地类型是否涉及链接问题,以及发出此错误时clang是否正确。


EDIT #2 : It has been determined that clang was correct to emit the error for the above code (see answer from @jxh), but that it incorrectly also emits an error for the following code (with using declaration moved from foo<Bar>() scope to main() scope): 编辑#2:已经确定clang对于上面的代码发出错误是正确的(参见@jxh的回答),但它错误地也为下面的代码发出错误( using声明从foo<Bar>()范围到main()范围):

 template<void(*FUNC_PTR)(void)> struct Func {}; template<typename T> extern inline void foo() {} int main() { struct Bar {}; using F = Func<foo<Bar>>; return 0; } 

By definition of no linkage in C++.11 §3.5 Program and linkage ¶2, I originally believed foo<Bar> has no linkage since it cannot be referred to by name by any other scope except that which defined the type Bar (ie, main() ). 根据C ++中没有链接的定义.11§3.5 程序和链接 ¶2,我原本认为foo<Bar>没有链接,因为它除了定义类型Bar (即main()之外的任何其他范围都不能通过名称引用main() )。 However, this is not correct. 但是,这是不正确的。 This is because the definition of a name with external linkage is described as: 这是因为具有外部链接的名称的定义描述为:

When a name has external linkage , the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit. 当名称具有外部链接时 ,其表示的实体可以通过其他翻译单元的范围或同一翻译单元的其他范围中的名称来引用。

And for a template function, this will always be the case. 对于模板功能,情况总是如此。 This is because there is one other scope from which the name can be referred. 这是因为可以引用名称的另一个范围。 Namely, the template function can refer to itself. 即,模板功能可以参考其自身。 Therefore, foo<Bar> has external linkage. 因此, foo<Bar>具有外部链接。 zneak's answer, EDIT 2 , has an e-mail thread with the clang developers confirming that foo<Bar> should have external linkage. zneak的回答,编辑2 ,有一个电子邮件线程与clang开发人员确认foo<Bar>应该有外部链接。

Thus, from C++.11 §14.3.2 Template non-type arguments ¶1: 因此,从C ++。11§14.3.2 模板非类型参数 ¶1:

A template-argument for a non-type, non-template template-parameter shall be one of: ... 模板参数的一个非类型,非模板的模板参数应是一个:...

  • a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-id s but excluding non-static class members, expressed (ignoring parentheses) as & id-expression , except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的对象的地址,或具有外部或内部链接的函数,包括函数模板和函数模板ID,但不包括非静态类成员,表达(忽略括号)作为& ID表达 ,除了&如果名称是指功能或阵列,并且如果相应的模板的参数是一个参考将被省略可省略; ... ...

  • The most relevant bullet is the third bullet. 最相关的子弹是第三个子弹。 Since foo<bar> has external linkage, passing it as a non-type template-parameter should be fine. 由于foo<bar>具有外部链接,因此将其作为非类型模板参数传递应该没问题。

    I'm late to the party, but standard says that type-local functions don't have linkage (§3.5:8): 我迟到了,但标准说类型本地函数没有链接(§3.5:8):

    Names not covered by these rules have no linkage. 这些规则未涵盖的名称没有链接。 Moreover, except as noted, a name declared at block scope (3.3.3) has no linkage . 此外,除非另有说明,否则在块范围(3.3.3)中声明名称没有链接

    Same section goes on to say: 同一节继续说:

    A type without linkage shall not be used as the type of a variable or function with external linkage unless 除非使用没有链接的类型,否则不应将其用作具有外部链接的变量或函数的类型

    • the entity has C language linkage (7.5), or 该实体具有C语言链接(7.5),或
    • the entity is declared within an unnamed namespace (7.3.1) , or 实体在未命名的命名空间(7.3.1)中声明 ,或
    • the entity is not odr-used (3.2) or is defined in the same translation unit. 该实体不是使用过的(3.2)或在同一翻译单元中定义。

    And, as a matter of fact, Clang will allow this: 而且,事实上,Clang将允许:

    namespace
    {
        template<void (*FUNC_PTR)(void)>
        struct Func {};
    
        template<typename T>
        void foo() {}
    }
    
    int main() {
        struct Bar {}; // function-local type
        Func<foo<Bar>> x;
    }
    

    And will reject it without the anonymous namespace. 并且将在没有匿名命名空间的情况下拒绝它。


    EDIT 1 : As jxh notes, the names are also defined in the same translation unit, so I'm not sure what to think of this one. 编辑1 :正如jxh所说,名称也在同一个翻译单元中定义,所以我不确定该怎么想这个。


    EDIT 2 : The guys at clang confirm it's a bug. 编辑2clang的家伙确认这是一个错误。

    声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

     
    粤ICP备18138465号  © 2020-2024 STACKOOM.COM