指向不完整类型的成员函数的指针

use*_*538 10 c++ pointer-to-member incomplete-type

我不明白为什么为类添加前向声明会将其指针的大小更改为成员类型

#include <iostream>
using namespace std;

int main()
{
    //struct CL;
    //cout<<sizeof(int (CL::*)())<<endl; 
    struct CL{};
    cout<<sizeof(int (CL::*)())<<endl;
}
Run Code Online (Sandbox Code Playgroud)

输出VS2013:
4

但是如果我取消注释main()中的前两行,那么输出是不同的:
16
16

因此,在struct CL的定义之前只添加一个前向声明只会增加指向CL成员的指针的大小.为什么?我知道成员函数指针的大小取决于类型的结构(例如,虚函数和基类可能会增加它),但为什么sizeof运算符可以应用于指向不完整类型成员的指针?还是不行?我没有在标准中找到它

dyp*_*dyp 7

MSVC编译器使用不同大小的指针来指向成员函数作为优化.此优化违反了标准.荣誉对伊戈尔Tandetnikreinterpret_cast一个MSDN形式后,[expr.reinterpret.cast] P10

甲prvalue类型的"指针的构件X类型的T1"可被明确地转换成不同类型的"指针的构件的prvalue Y类型的T2"如果T1T2都函数类型或两者的对象类型.空成员指针值将转换为目标类型的空成员指针值.除以下情况外,此转换的结果未指定:

  • 将"指向成员函数的指针"类型的prvalue转换为指向成员函数类型的不同指针,并返回其原始类型,从而生成指向成员值的原始指针.

因此有一个往返保证,这有效地迫使符合实现对所有指向成员函数类型的指针使用相同的大小.


如果设置了/vmb开关,则执行MSVC优化.对于单继承的情况,指向成员函数的优化指针只需要一个void*大小的存储,参见The Old New Thing:指向成员函数的指针是非常奇怪的动物.

如果你只是向前声明类型CL然后形成一个指向成员的函数,那么优化有望被取消(遗憾的是我找不到任何文档).否则,您可能会在定义之前和之后获得不一致的大小CL.

顺便说一下,如果在不指定基础类型的情况下对它们进行前向声明,然后明确定义枚举定义的基础类型,则可以在VS2010中获取枚举的不一致大小.这仅适用于激活的语言扩展.