类模板的注入类名 [英] Injected-class-names of class templates

查看:99
本文介绍了类模板的注入类名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此答案中的代码启发。考虑:

 模板< class> 
class A {};

int main()
{
A< float> a(A< float> :: A< int>());
return 0;是这个代码



<$ p









  1. 错误,因为 A< float> :: A 命名构造函数(根据§3.4.3.1[class.qual] / p2 )并且不能在此上下文中使用(加上< int> 将完成无法解析)或

  2. template-name 作为 inject-class-name A< float> :: A >(§14.6.1[temp.local]),使得 A :: A 意味着与 A < ; int> a 被声明为函数(由于最烦琐的语法分析)?



    1. g ++说1. clang说2 ICC 13 。哪个编译器是正确的?

      解决方案

      gcc



        //减少测试用例
      template< class T>
      class A {};

      int main(){
      A< float> :: A< int> X; //形式不正确,在clang和icc中的错误
      }

      在上面的简化测试用例中,我们有一个 nested-name-specifier A< float> :: / em> A ,然后是一些乱码(< int> )。



      这是因为出现 nested-name-specifier 的上下文要求在查找期间包含函数名(意味着构造函数是



      相关的错误报告::








      > >

       <$ c>(提名一个类)不包括函数(因此,没有找到构造函数的上下文) $ c> 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






      类成员 / strong> [class.qual]


      不会忽略 88 nested-name-specifier 指定类 C




      • 如果在 C 中查找 nested-name-specifier 之后指定的名称是< (7.3.3)中的 C (第9条)或

      • 如果在 nested-name-specifier 之后指定的名称与标识符 simple-template-id



      名称的最后一个组件中的模板名称



      [ :...]

      >

      这样的构造函数名称只能在声明的 declarator-id 中使用,该声明命名构造函数或在一个 using-






      88。查找函数名称被忽略的名称包括名称出现在 nested-name-specifier 阐述类型说明符基本说明符 >







      14.6 .1p2 本地声明的名称 [temp.local]



      < blockquote>

      类似于普通(非模板)类,类模板有一个注入类名
      (第9条)。 inject-class-name可以用作模板名称
      类型名称



      模板参数列表配合使用时,作为模板模板参数
      模板参数 >,或者作为朋友类模板
      声明的 elaborated-type-specifier 中的最终
      标识符,它引用类模板本身。



      否则,
      等同于模板名称,后跟
      类别的模板参数


      Inspired by the code in this answer. Consider:

      template<class>
      class A { };
      
      int main()
      {
          A<float> a(A<float>::A<int>());
          return 0;
      }
      

      Is this code

      1. ill-formed, because A<float>::A names the constructor (per §3.4.3.1 [class.qual]/p2) and cannot be used in this context (plus the <int> would complete fail to parse anyway), or
      2. well-formed, with A<float>::A being the injected-class-name, used as a template-name (§14.6.1 [temp.local]), such that A<float>::A<int> means exactly the same as A<int>, and a being declared as a function (due to the most vexing parse)?

      g++ says 1. clang says 2, and so does ICC 13. Which compiler is correct?

      解决方案

      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:


      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 <>.

      这篇关于类模板的注入类名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆