类模板的注入类名称

T.C*_*.C. 17 c++ templates language-lawyer

灵感来自这个答案中的代码.考虑:

template<class>
class A { };

int main()
{
    A<float> a(A<float>::A<int>());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是代码

  1. A<float>::A格式错误,因为命名构造函数(根据§3.4.3.1[class.qual]/p2)并且不能在此上下文中使用(加上<int>完全无法解析),或者
  2. 良好的,与A<float>::A作为注射类名,用作模板的名称(§14.6.1[temp.local]),使得A<float>::A<int>装置完全一样A<int>,并且a被声明为函数(由于最烦恼的解析)?

g ++说1. clang说2,ICC 13也是如此.哪个编译器正确?

Fil*_*efp 8

gcc是正确的; 你的片段格式不正确!

// reduced testcase
template<class T>
class A { };

int main () {
  A<float>::A<int> x; // ill-formed, bug in `clang` and `icc`
}
Run Code Online (Sandbox Code Playgroud)

在上面简化的测试用例中,我们有一个嵌套的名称说明符,A<float>::后跟一个非限定的id A,然后是一些乱码(<int>).

这是因为嵌套名称说明符出现的上下文要求在查找期间包含函数名称(意味着首先找到构造函数,并且表达式格式错误).


相关错误报告:


如何规避" 问题 "?

有些上下文通过嵌套名称说明符(指定类)查找的成员名称不应包含函数(因此,找不到构造函数的上下文),下面是几个示例:

template<class T>
struct A {
  typedef T value_type;
};
Run Code Online (Sandbox Code Playgroud)
  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
Run Code Online (Sandbox Code Playgroud)

标准说什么?

3.4.3.1p2 班级成员 [class.qual]

在查找中,函数名称不被忽略88嵌套名称说明符指定类C:

  • 如果在C中查找,在嵌套名称说明符之后指定的名称是C的注入类名(第9条),或者
  • 如果在nested-name-specifier之后指定的名称与最后一个组件中的标识符simple-template-idtemplate-name相同,则在using声明(7.3.3)中是一个成员声明*nested-name-specicifier的内容,

而是将该名称视为命名C类的构造函数.

[ :......]

这样的构造函数名称只能用于命名构造函数或using-declaration的声明declarator-id.


88.忽略函数名称的查找包括出现在嵌套名称说明符,详细说明类型说明符基本说明符中的名称.

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

与普通(非模板)类一样,类模板具有注入类名(第9节).inject-class-name可以用作模板名称类型名称.

当它与template-argument-list一起使用时,作为 模板模板参数的模板参数,或作为友元类模板声明的详细类型说明符中的最终标识符,它引用类模板本身.

否则,它等同于template-name,后跟括在其中的类模板的template-parameters<>.