显然clang认为decltype(this)
是指向cv限定类的指针,而gcc认为它是指向cv限定类的指针的 const引用。 GCC只认为decltype(&*this)
是指向cv限定类的指针。当它用作模板的类型名称时,这会产生一些影响。考虑一个假设的例子:
template<typename T>
class MyContainer {
/* ... */
template<typename ContainerPtr>
class MyIterator {
ContainerPtr container;
/* ... */
};
auto cbegin() const
-> MyIterator<decltype(&*this)> { return { /* ... */ }; }
auto cend() const
-> MyIterator<decltype(this)> { return { /* ... */ }; }
};
在此示例中,实现了T
的自定义容器。作为容器,它支持迭代器。实际上,有两种迭代器:iterator
和const_iterator
。复制这两个代码是没有意义的,因此可以编写一个模板迭代器类,获取指向原始类MyContainer<T> *
的指针或指向const版本MyContainer<T> const *
的指针。
当cbegin
和cend
一起使用时,gcc会出错,说它推断出冲突的类型,而clang只是正常工作。
答案 0 :(得分:17)
好的,这是我在标准(N3337)中找到的内容:
7.1.6.2简单类型说明符[dcl.type.simple]
4
decltype(e)
表示的类型定义如下:
- 如果e
是不明白的 id-expression 或者 未加密级的类成员访问(5.2.5),decltype(e)
是类型 由e
命名的实体。如果没有这样的实体,或者e
命名一组重载函数,程序格式不正确;
- 否则,如果e
是xvalue,则decltype(e)
是T&&
,其中。{T
的类型为e
; - 否则,如果e
是左值,decltype(e)
为T&
,其中T
是e
的类型;
- 否则,decltype(e)
是e
的类型。
操作数decltype
说明符是未评估的操作数(第5条)。
和
5.1.1一般[expr.prim.general]
3如果声明声明了成员函数或成员函数 类
X
的模板,表达式this
是类型的prvalue “可选 cv-qualifer-seq 之间指向 cv-qualifier-seqX
的指针 和函数定义,成员声明符的结尾,或 声明符的。它不会出现在可选的 cv-qualifier-seq 之前 它不应出现在静态成员的声明中 函数(虽然它的类型和值类别是在一个 静态成员函数,因为它们在非静态成员中 功能)。 [注意:这是因为不会发生声明匹配 直到知道完整的声明者。 - 结束音符]与对象不同 在其他上下文中,*this
的表达式不需要是完整的 类型用于成员之外的类成员访问(5.2.5) 功能体。 [注意:只有在此之前声明的类成员 声明是可见的。 - 结束说明]
之前对§9.3.2的引用是一个错误,因为它处理成员函数的 body ,如下面in a comment by MWid所述。
<德尔> 9.3.2`his`指针[class.this] 1在非静态(9.3)成员函数体中, 关键字`this`是一个prvalue表达式,其值是地址 调用该函数的对象。 a中的“this”类型 类`X`的成员函数是`X *`。如果成员函数是 声明`const`,`this`的类型是`const X *`,如果是成员 函数声明为`volatile`,`this`的类型是`volatile X *`, 如果成员函数声明为`const volatile`,则为 `this`是`const volatile X *`。 德尔>
所以看起来gcc错了。
答案 1 :(得分:14)