为什么在编译时获取类成员变量地址会导致 C2327 和 C2065?

Why does getting the class member variable address at compile time result in C2327 and C2065?

提问人:Vaillancourt 提问时间:9/20/2023 更新时间:9/20/2023 访问量:59

问:

我有以下代码块,它们在一个简单的、新创建的 hello world VS2017 项目中“工作”,并且在我们拥有的另一个应用程序中,但由于某种原因我无法识别,当我将其移植到我正在处理的当前应用程序时,它没有“工作”。

/**
 * This can be used to associate a class variable to a type and a string in order
 *  to load it easily from XML or JSON.
 */
template<typename Class, typename T>
struct Property {
  constexpr Property( T Class::*aMember, const char* aName )
    : member { aMember }, name { aName } {}

  using Type = T;
  using ClassType = Class;

  T Class::*member;
  const char* name;
};

struct MajorPaine
{
  int mInt;

  // All errors are "spammed" by the following line:
  static constexpr auto perp = Property<MajorPaine, decltype(MajorPaine::mInt)>{ 
    &MajorPaine::mInt, "int" };
};

当我编译此代码时,我收到这些错误(使用 Microsoft (R) C/C++ 优化编译器版本 19.16.27034 for x86 编译):

error C2327: 'MajorPaine::mInt': is not a type name, static, or enumerator
error C2065: 'mInt': undeclared identifier
fatal error C1903: unable to recover from previous error(s); stopping compilation

错误的原因可能是什么?

C++ 可视化工作室 2017

评论


答:

1赞 Vaillancourt 9/20/2023 #1

回答我自己的问题,以帮助人们避免在这个(以及我未来的自己)上花费数小时。


tldr:未设置编译器标志。设置它确实修复了它。/permissive-

根据 /permissive- 标志的帮助页面

[...]编译器还实现了两阶段名称查找的更多要求。设置 /permissive- 选项后,编译器将分析函数和类模板定义,并标识模板中使用的依赖名称和非依赖名称。[...]

因此,我假设这两个错误都源于编译器在读取结构时执行了一次传递,并且还不知道它确实存在。允许编译器执行两个阶段,允许它查看成员并实际使用它。mInt

值得注意的是,“[...]默认情况下,在 Visual Studio 2017 版本 15.5 及更高版本创建的新项目中设置 /permissive- 选项。[...]".这就解释了为什么它在新创建的 VS 项目中运行良好,并且在我之前参与的项目中运行良好,但在我当前的项目中却运行不正常(因为它是不久前创建的)。