Injected-class-names of class templates

前端 未结 1 826
眼角桃花
眼角桃花 2020-12-31 03:38

Inspired by the code in this answer. Consider:

template
class A { };

int main()
{
    A a(A::A());
    re         


        
相关标签:
1条回答
  • 2020-12-31 04:05

    gcc is correct; your snippet is ill-formed!

    // reduced testcase
    template<class T>
    class A { };
    
    int main () {
      A<float>::A<int> x; // ill-formed, bug in `clang` and `icc`
    }
    

    In the above reduced testcase we have a nested-name-specifier, A<float>::, followed by an unqualified-id A, which is then followed by some gibberish (<int>).

    This is because the context in which the nested-name-specifier appears mandates that, during a look-up, function names are included (meaning that the constructor is found first, and the expression is ill-formed).


    Relevant Bug Reports:

    • llvm.org/bugs/ - #8263; Incorrect constructor name resolution

    How to circumvent the "problem"?

    There are contexts in which member names that are looked up through a nested-name-specifier (that nominates a class) shall not include functions (hence, contexts where the constructor is not found), below are a few examples:

    template<class T>
    struct A {
      typedef T value_type;
    };
    
      struct A<float>::A<int>  x;     // ok, context: elaborate-type-specifier
    typename A<float>::A<int> ();     // ok, context: [expr.type.conv]p1
      A<float>::A::value_type  x;     // ok, context: nested-name-specifier
    
    
    struct X : A<float>::A<int> { };  // ok, context: base-specifier
    

    What does the Standard say?

    3.4.3.1p2 Class members [class.qual]

    In a lookup in which function names are not ignored88 and the nested-name-specifier nominates a class C:

    • if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9), or
    • in a using-declaration (7.3.3) that is a member-declaration, if the name specified after the nested-name-specifier is the same as the identifier or the simple-template-id's template-name in the last component of the *nested-name-specicifier,

    the name is instead considered to name the constructor of class C.

    [ Note: ... ]

    Such a constructor name shall be used only in the declarator-id of a declaration that names a constructor or in a using-declaration.


    88. Lookups in which function names are ignored include names appearing in a nested-name-specifier, an elaborated-type-specifier, or a base-specifier.

    14.6.1p2 Locally declared names [temp.local]

    Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name.

    When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself.

    Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.

    0 讨论(0)
提交回复
热议问题