为什么decltype(class :: class :: class :: member)有效

时间:2016-06-06 07:46:21

标签: c++ c++11 decltype

我意外地注意到这段代码编译并正常工作:

struct M { int some_int; };
static_assert(std::is_same<
                   decltype(M::M::M::M::some_int) /* <- this */,
                   int>::value, "Types must be int");

为什么这是正确的(decltype(M::M::M::M::some_int) <=> decltype(M::some_int))?

可以使用class::class::...::member这个模式的其他构造吗?

编译器:用于x86的Microsoft(R)C / C ++优化编译器版本19.00.23824.1

2 个答案:

答案 0 :(得分:10)

这在所有情境中均有效,而不仅仅是decltype。类包含自己的名称作为注入的类名。因此,在类A::B::M中,注入名称M以引用类A::B::M。这意味着,如果您真的想要,可以使用M::M::M::some_member来引用该类的成员。

[Live example]

请注意,仅提及类名本身(例如M::M::M)时,情况略有不同。如果这样的引用发生在对函数的引用也可能正确的地方,则采用语法来引用构造函数。但是,在仅类型的上下文中,即使这样的引用也是有效的。例如:

M::M::M m;  // illegal, M::M interpreted as reference to constructor

struct D : public M::M::M  // legal, a function could not be references here, so M::M::M means M
{};

答案 1 :(得分:9)

这是因为 inject-class-name

  

(N3337) [class]/2:在看到类名后立即将类名插入到作用域中。   类名也插入到类本身的范围内;这被称为注入类名。   出于访问检查的目的,inject-class-name被视为公共成员名称。 [...]

所以你可以随意嵌套这些,并且他们也可以使用派生类型:

struct A { using type = int; };
struct B : public A {};

using foo = B::B::B::A::A::A::type;

请注意,对于A[::A]*::A,可以考虑使用inject-name来命名构造函数:

  

[class.qual]/2:在查找中,构造函数是可接受的查找结果,并且嵌套名称说明符指定   一个班级C

     

- 如果在C中查找时,在嵌套名称说明符之后指定的名称是注入类名   C(第9条)或

     

- [...]

     

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