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

typeid doesn't work with non-static member function

本文关键字:静态成员 函数 适用于 不适用 typeid      更新时间:2023-10-16

clang不会编译对下面typeid的第三次调用(请参阅实时示例)。但是我在 §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';
}

据我所知clang是正确的,如果它是数据成员,则使用非静态成员仅在未计算的上下文中有效。因此,对于前两种情况,看起来gcc不正确,但在sizeofdecltype的情况下gcc正常工作,它们也有未计算的操作数。

从草案C++11标准部分5.1.1[expr.prim.general]

表示非静态

数据成员或非静态数据的 id 表达式 类的成员函数只能用于:

并包括以下项目符号:

如果该 id-expression 表示非静态数据成员并且它出现 在未计算的操作数中。[ 示例:

struct S {
    int m;
};
int i = sizeof(S::m); // OK
int j = sizeof(S::m + 42); // OK 

—结束示例 ]

其余项目符号不适用,它们如下:

  • 作为类成员访问 (5.2.5) 的一部分,其中对象表达式引用成员的类 61 或派生自该类的类61 类,或
  • 形成指向成员的指针 (5.3.1),或
  • 在该类的
  • 构造函数或从该类派生的类 (12.6.2) 的 MEM 初始值设定项中,或
  • 在大括号或等于初始值设定项中,用于该类或派生自该类的类的非静态数据成员 (12.6.2),或

我们知道操作数未从第 5.2.8 节中计算,该节说:

当 typeid 应用于 glvalue 以外的表达式时 多态类类型, [...]表达式是未计算的操作数 (第5条)。

我们可以从语法中看到,id-表达式要么是非限定id,要么是限定id

id-expression:
    unqualified-id
    qualified-id

更新

提交 gcc 错误报告:typeid 不允许表示非静态数据成员的 id 表达式。

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?