已注入类模板的类名

Injected-class-names of class templates

本文关键字:注入      更新时间:2023-10-16

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

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

这个代码是吗

  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也是。哪个编译器是正确的?

gcc正确;你的代码片段格式不正确

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

在上面的简化测试用例中,我们有一个嵌套的名称说明符A<float>::,后面跟着一个不合格的idA,后面跟着一些胡言乱语(<int>)。

这是因为嵌套名称说明符出现的上下文要求在查找过程中包括函数名(意味着首先找到构造函数,并且表达式格式不正确)。


相关错误报告

  • llvm.org/bugs/-#8263;构造函数名称解析不正确

如何规避"问题"

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

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

标准是怎么说的

3.4.3.1p2类成员[class.qual]

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

  • 如果在C中查找时,在嵌套名称说明符之后指定的名称是C的注入类名(第9条),或者
  • 在作为成员声明的using声明(7.3.3)中,如果在嵌套名称说明符之后指定的名称与*嵌套名称说明符的最后一个组件中的identifier简单模板id模板名称相同

该名称被认为是为类C的构造函数命名。

[注意:…]

此类构造函数名称只能在命名构造函数的声明的声明符id中使用,或在使用声明时使用。


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

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

与普通(非模板)类一样,类模板有一个注入的类名(第9条)。注入的类名可以用作模板名键入名称

当它与模板参数列表一起使用时,作为模板模板参数的模板自变量,或作为最终参数友元类模板的详细说明的类型说明符中的标识符声明,它引用类模板本身。

否则,就是等效于CCD_ 15中包含的类模板。