clang
未编译下面对typeid
的第三次调用(请参阅live example)。但我在§5.2.8中看不到任何禁止这一点的内容,特别是当我们认为表达式B::f
不是多态类类型的glvalue时(见第3段)。此外,根据此段,表达式B::f
是未评估的操作数,因此,调用typeid(B::f)
应该编译。请注意,GCC
不会编译以下对typeid
的任何调用:
#include <iostream>
#include <typeinfo>
struct A{ int i; };
struct B{ int i; void f(); };
int main()
{
std::cout << typeid(A::i).name() << '\n';
std::cout << typeid(B::i).name() << '\n';
std::cout << typeid(B::f).name() << '\n';
}
答案 0 :(得分:11)
据我所知clang
是正确的,使用非静态成员仅在未评估的上下文中才有效(如果它是数据成员)。因此,对于前两种情况,gcc
似乎不正确,但gcc
和sizeof
的情况下decltype
也能正常工作,而5.1.1
和struct S {
int m;
};
int i = sizeof(S::m); // OK
int j = sizeof(S::m + 42); // OK
也有未评估的操作数。
来自draft C++11 standard部分5.2.8
[expr.prim.general] :
表示非静态数据成员或非静态数据的id表达式 只能使用类的成员函数:
并包含以下项目符号:
如果该id-expression表示非静态数据成员并且它出现 在一个未评估的操作数。 [例如:
id-expression: unqualified-id qualified-id
-end example]
其他子弹不适用,它们如下:
- 作为类成员访问(5.2.5)的一部分,其中对象表达式引用成员的类 61 或从中派生的类 上课,或
- 形成指向成员(5.3.1)或
的指针- 在mem-initializer中,用于该类的构造函数或从该类派生的类(12.6.2),或
- 在该类的非静态数据成员或从该类派生的类(12.6.2)的支持或等于初始化程序中,或
我们知道操作数未在{{1}}部分中评估:
当typeid应用于除了glvalue之外的表达式 多态类类型,[...]表达式是未评估的操作数 (第5条)。
我们可以从语法中看出 id-expression 是 unqualified-id 或 qualified-id :
{{1}}
更新
提交了gcc bug report: typeid does not allow an id-expression that denotes a non-static data member。
答案 1 :(得分:1)
typeid(A::i).name()
并不像我想的那样做。我希望它是一个指向成员的指针,但它实际上只是一个int
。
要查看此信息,请运行以下代码:
#include <iostream>
struct A{ int i; };
struct B{ int i; void f(void); };
template<typename T>
void what_is_my_type() {
std:: cout << __PRETTY_FUNCTION__ << std:: endl;
}
int main()
{
what_is_my_type<decltype(&A::i)>(); // "void what_is_my_type() [T = int A::*]"
what_is_my_type<decltype(&B::i)>(); // "void what_is_my_type() [T = int B::*]"
what_is_my_type<decltype(&B::f)>(); // "void what_is_my_type() [T = void (B::*)()]"
what_is_my_type<decltype(A::i)>(); // "void what_is_my_type() [T = int]"
what_is_my_type<decltype(B::i)>(); // "void what_is_my_type() [T = int]"
// what_is_my_type<decltype(B::f)>(); // doesn't compile
}
我在每次通话后都将输出放在评论中。
前三个调用按预期工作 - 所有三个工作和类型信息包括结构类型(A
或B
)以及成员类型。
最后三个是不同的。最后一个甚至不编译,前两个只打印int
。我认为这是一个错误的线索。在给定特定A
或B
的情况下,可以获取该特定成员的地址:
A a;
int * x = &(a.i);
*x = 32;
但不可能(甚至有意义?)这样做:
B b;
??? y = &(a.f); // what does this even mean?
最后,要强调这不是关于指针,请考虑一下:
A a;
B b;
int x = a.i;
int y = b.i;
??? z = b.f; // what would this mean? What's its type?