typeid不适用于非静态成员函数

时间:2015-01-20 19:30:25

标签: c++ c++11 language-lawyer typeid

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';
}

2 个答案:

答案 0 :(得分:11)

据我所知clang是正确的,使用非静态成员仅在未评估的上下文中才有效(如果它是数据成员)。因此,对于前两种情况,gcc似乎不正确,但gccsizeof的情况下decltype也能正常工作,而5.1.1struct 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

}

我在每次通话后都将输出放在评论中。

前三个调用按预期工作 - 所有三个工作和类型信息包括结构类型(AB)以及成员类型。

最后三个是不同的。最后一个甚至不编译,前两个只打印int。我认为这是一个错误的线索。在给定特定AB的情况下,可以获取该特定成员的地址:

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?