typeid 不适用于非静态成员函数
typeid doesn't work with non-static member function
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
不正确,但在sizeof
和decltype
的情况下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
}
我在每次调用后将输出放在注释中。
前三个调用按预期工作 - 所有三个调用都工作,类型信息包括结构的类型(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?
- 如何在C++中使用非静态成员函数作为回调函数
- 静态成员函数使用相同的名称时出现模板类型名称错误
- 在 nullptr 上调用无状态类的非静态成员函数是否合法?
- 为什么传递非静态成员函数会导致编译错误?
- 处理类内的回调时,必须调用对非静态成员函数的引用
- 非静态成员函数的 decltype 格式不正确吗?
- std::异步与非静态成员函数
- C++无效使用非静态成员函数?
- 未使用的C++未优化的静态成员函数/变量
- C++:如何返回指向非静态成员函数的指针?
- 使用静态成员函数而不是普通函数是否有任何开销?
- 在 stream_descriptor::async_wait 中无效使用非静态成员函数
- 为什么我不能像这样在静态成员函数中调用静态成员变量?
- 无法在clang Linux中分配非静态成员函数,但我可以在Visual Studio Windows中分配
- 在类定义中推导内联静态成员函数的返回类型
- `enable_if()`以禁用模板化类的静态成员函数声明
- 错误:无效使用非静态成员函数"int test::hotplug_callback(libusb_contex
- 常量静态成员函数
- 使用 vector.sort() 的非静态成员函数无效使用
- 从静态成员函数访问私有非静态类变量 - C++