注入的类名称为类型

问题描述 投票:14回答:2

鉴于以下代码,

template <class> using void_t = void;
template <class C, class = void> struct X { enum { v = 0 }; };
template <class C> struct X<C, void_t<typename C::T> > { enum { v = 1 }; };
struct T { };
int main() { return X<T>::v; }

什么应该主要回归? GCC和MSVC说1,Clang说0。

c++ language-lawyer c++17
2个回答
9
投票

我认为Clang就在这里。 [class.qual]的规则是:

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

  • 如果在C中查找的嵌套名称说明符之后指定的名称是C([class])的注入类名,或者
  • [......这里无关紧要......]

而是将该名称视为命名类C的构造函数。 [注意:例如,构造函数在详细类型说明符中不是可接受的查找结果,因此不会使用构造函数来代替inject-class-name。 - 结束注释]这样的构造函数名称只能用于命名构造函数或using-declaration的声明的declarator-id。 [实施例:

struct A { A(); };
struct B: public A { B(); };

A::A() { }
B::B() { }

B::A ba;            // object of type A
A::A a;             // error, A​::​A is not a type name
struct A::A a2;     // object of type A

- 结束例子]

typename C::TA::A是同一类,它的查找函数名称不被忽略(typename不会导致函数名被忽略)。因此,在typename C::T中,当CT时,T这个名称被认为是构造函数的名称。由于它不是类型名称,我们应该获得替换失败并回退到主模板。

提起86818


4
投票

为了完成Barry的回答,typename只对编译器说,以下名称是模板实例化之前执行的分析的类型。实例化后,执行名称查找,就好像typename不存在一样,[temp.res]/4

即使存在typename,通常使用限定名称查找来查找qualified-id。

所以Clang是对的。为了获得一致的编译器行为,您可以使用elaborated type specifier struct C::T代替typename C::T

template <class> using void_t = void;
template <class C, class = void> struct X { enum { v = 0 }; };
template <class C> struct X<C, void_t<struct C::T> > { enum { v = 1 }; };
struct T { };
int main() { return X<T>::v; }
© www.soinside.com 2019 - 2024. All rights reserved.