成员指针的C ++类内初始化使MSVC失败(但GCC / Clang起作用)

i.s*_*tav 8 c++ visual-studio visual-c++

这是一个非常简单的C ++代码:

#include <iostream>

struct A
{
    int a;
    constexpr static int A::* p = &A::a;
    virtual void f() {}
};
int main()
{
    A x; x.a = 0;
    x.*(A::p) = 1234;
    std::cout << x.a;
}
Run Code Online (Sandbox Code Playgroud)

更令人震惊的是,这段代码在GCC,Clang和MSVC之间显示了不同的结果。

我已经尝试了4个编译器

  1. GCC:编译良好,打印1234

  2. 叮当声:编译良好,打印1234

  3. MSVC(在线):无法编译。

  4. 带有Visual Studio 2019的MSVC(本地):可以很好地编译,打印0。(有趣的是,如果我将f()其删除,则会打印出来1234。)

我不确定使用其自己的成员进行的指向成员的指针的类内初始化是否合法,但我相信该代码应该可以打印1234

Compiler ExplorerRextester上试用

我不知道谁是对的。(至少4.似乎是一个错误)

编辑-我发现3.和4.的区别来自编译器选项/permissive。但是/permissive和和的结果/permissive仍然与gcc和clang不同。

Win*_*ing 0

更新

这是稍作修改的代码,在 Visual Studio 2019 中似乎按您的预期工作:

struct A
{
    int a;
    constexpr static int A::* p() { return &A::a; }
    virtual void f() {}
};

using namespace std;
int main()
{
    A x;
    void* px = &x;
    x.a = 0;
    x.*(A::p()) = 1234;
    cout << x.a << endl;

    getchar();
}
Run Code Online (Sandbox Code Playgroud)

更新结束


刚刚在 Visual Studio 2019 上尝试过,我将代码修改为:

#include <iostream>

struct A
{
    int a;
    constexpr static int A::* p = &A::a;
    virtual void f() {}
};

struct B
{
    int a;
    constexpr static int B::* p = &B::a;
};

using namespace std;

void printBytes(void* p, size_t length = 16) {
    uint8_t* pu = (uint8_t*)p;
    cout << "  ";
    for (size_t i = 0; i < length; ++i) {
        auto val = *(pu + i);
        printf("%02x ", val);
    }
    cout << endl;
}

int main()
{
    A x;
    void* px = &x;
    cout << "\nfor A:\n";
    printBytes(px);
    x.a = 0;
    printBytes(px);
    x.*(A::p) = 0x1234;
    printBytes(px);
    cout << x.a << endl;

    B y;
    void* py = &y;
    cout << "\nfor B:\n";
    printBytes(py);
    y.a = 0;
    printBytes(py);
    y.*(B::p) = 0x1234;
    printBytes(py);
    cout << y.a << endl;

    getchar();
}
Run Code Online (Sandbox Code Playgroud)

输出是:


for A:
  fc 9c 2c 01 cc cc cc cc cc cc cc cc 0f 40 04 09
  fc 9c 2c 01 00 00 00 00 cc cc cc cc 0f 40 04 09
  34 12 00 00 00 00 00 00 cc cc cc cc 0f 40 04 09
0

for B:
  cc cc cc cc cc cc cc cc cc cc cc cc 60 fd 3d 01
  00 00 00 00 cc cc cc cc cc cc cc cc 60 fd 3d 01
  34 12 00 00 cc cc cc cc cc cc cc cc 60 fd 3d 01
4660
Run Code Online (Sandbox Code Playgroud)

B情况按预期工作,但对于A 情况,上面的输出表明这一行:

x.*(A::p) = 0x1234;

写入0x1234“指向虚拟函数表的指针”占用的位置。

因此,我认为Visual Studio 2019 的编译器在具有虚拟成员函数的结构(类)上的表达式(获取指向成员变量的指针)犯了错误。&A::a