指向成员变量作为静态成员的指针

问题描述

这些天,我一直在研究一个数据模型的项目研究,该模型具有一种适合我的需求的反映。 当我使用最新的稳定版g ++进行我的第一篇研究时,我在Visual Studio 19中失败了。太糟糕了,因为后者是我的主要平台……

有效地,我尝试将指向成员变量的指针存储到另一个静态成员变量中。因此,对我而言,真正实现此内联(以适应我的更大概念)确实很理想。

我将失败的细节简化为以下MCVE:

struct Field { };

struct Class {
    
  template <typename CLASS>
  struct BuiltInInfoT {
    Field CLASS::*const pField; // member pointer
  };
  
};

struct Object: Class {
  Field field1;
  static inline BuiltInInfoT<Object> field1BuiltInfo = { &Object::field1 };
};

int main()
{
  Object obj;
}

感到困惑的是,这似乎可以在g ++中工作,但不能在MSVC中工作,我看看Compiler Explorer,其他编译器对此有何评论。因此,我发现最近的clang甚至最近的ICC(我以前从未使用过)都接受这一点。

Live Demo on Compiler Explorer

我尝试了一个更简单的先前示例,其中没有使用任何模板:

#include <iostream>

struct Test {
  struct Info { int Test::*p; };
  int a;
  static inline Info infoA = { &Test::a };
  int b;
  static inline Info infoB = { &Test::b };
  
  Test(int a,int b): a(a),b(b) { }
};

#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  DEBUG(Test test(123,456));
  DEBUG(std::cout << (test.*(test.infoA.p)) << '\n');
  DEBUG(std::cout << (test.*(test.infoB.p)) << '\n');
}

结果是相同的:g ++,clang和ICC可以很好地编译,但是MSVC抱怨。

Live Demo on Compiler Explorer

所以,现在我有点不确定了。

是否值得报告MSVC的错误?还是我期待我不应该依赖的东西?


免责声明:

当然,最近3天内我在Google上进行了搜索,发现了无数关于如何使用成员指针的教程-包括我自己写的SO: What is the meaning of this star (*) symbol in C++? — Pointer to member的答案。也许我错过了基本关键字,但我保证我真的很努力。


以防万一,您想知道我要做什么...

实际的项目研究为Live Demo on coliru,是我根据上述研究得出的MCVE。


更新

经过长时间的讨论,@ doug帮助我发现这似乎是Visual Studio属性设置的主题。通过一个干净的启动项目,我在本地VS 2019中运行了上述所有示例。(之前,我照常使用CMake生成的项目。)我将比较两个resp的选项。 VS项目找出了显着的差异,如果发现一些问题,请发布更新…

解决方法

@doug给我的提示是他让我的代码在VS 2019中运行而没有任何抱怨。

漫长的聊天之后,他给了我提示,以在新创建的VS解决方案中测试我的上述示例。我要做的就是启用C ++ 17(/std:c++17),然后MSCV毫无疑问地编译了所有示例。

我必须承认,我通常使用CMake来准备VS解决方案:

project (OFM)

cmake_minimum_required(VERSION 3.10.0)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

include_directories("${CMAKE_SOURCE_DIR}")

file(GLOB sources *.cc)
file(GLOB headers *.h)

add_executable(testOFM
  ${sources} ${headers})

因此,我不得不在VS项目设置中找到相关的区别。 终于,我找到了:

  • VS创建的项目包含/permissive-
  • 不是由CMake创建的项目。

在项目设置中,是

- C/C++
  - Language
    - Standards conformance: Yes (/permissive)

MS在线文档:

/permissive- (Standards conformance)

为编译器指定标准一致性模式。使用此选项可以帮助您识别和修复代码中的一致性问题,使其更加正确和可移植。

这正是我想要的:要符合标准且可移植

在我的CMake生成的项目中调整此选项,我也将其编译并运行。

正确编译了Compiler Explorer上的演示(使用足够的命令行参数):

Live Demo on Compiler Explorer

Live Demo on Compiler Explorer

甚至是最初的研究(我的麻烦从何而来):

Live Demo on Compiler Explorer


我想知道的是:当我编写CMake脚本时,我已经使用过

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

明确意图符合标准且可移植

因此,似乎还需要在CMake中进行其他设置。 (最后一招可能是针对特定平台的设置,但如果可能的话,我会进行调查以查找其他内容。)


关于我的问题,我发现了
CMake Issue #17068:
MSVC toolset 14.1+: Set /permissive- when CXX_EXTENSIONS==OFF?


在使用编译器特定的选项修复了CMake脚本后:

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if (MSVC)
  add_compile_options(/permissive-)
endif()

并再次生成我的VS解决方案/项目,并且编译后的代码也没有任何抱怨。

,

@Scheff发现了可能影响其他重新内联静态成员初始化的问题。这特别成问题,因为它以不同的方式影响编译器资源管理器c ++ 17默认值与MSVC IDE c ++ 17默认值。 查看他的答案和分析:

使用MSVC的默认c ++设置(c ++ 14),该设置不允许嵌入式静态成员。

将设置更改为c ++ 17或更高版本。这是在同一行上进行内联静态初始化的常见原因。

但是,聊天之后,事实证明正在使用c ++ 17,但是区别在于它与CMake一起使用。显然,CMake与MSBuild解决方案/项目文件之间存在差异。后者有效,前者无效。正在调查中,并将更新结果。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...