如何以编程方式获取 /permissve- 在 VS2017 Update8.2 中设置的所有编译器标志

Posted

技术标签:

【中文标题】如何以编程方式获取 /permissve- 在 VS2017 Update8.2 中设置的所有编译器标志【英文标题】:How to get programatically all the compiler flags set by /permissve- in VS2017 Update8.2 【发布时间】:2018-11-27 12:00:14 【问题描述】:

如何以编程方式获取 Visual Studio 2017 编译器标志 /permissive- 启用的选项

根据 Microsoft 文档 /permissive- 标志设置 /Zc 编译器选项以实现严格一致性

现在下面的代码在 Visual Studio 2017 Update8.2 上编译,仅打开 /permissive- 编译器标志,当 /permissive- 标志未打开时失败(在 Vs2017 Update 8.2 上)

#include <sstream>

namespace ABC 

template <typename T>

bool operator|(T v1, T v2) 


std::stringstream ss_; //commenting this removes the error

using namespace ABC;

int main() 
return 0;

我想知道 /Zc 的哪个编译器标志修复了这个问题

【问题讨论】:

【参考方案1】:

没有/permissive- 会出现问题,因为编译器不会对模板执行正确的两阶段名称查找。

在 sstream 中,第 270 行你会发现:

            …
            constexpr auto _Both = ios_base::in | ios_base::out;
            …

作为std::basic_stringbuf::seekoff() 定义的一部分,它是一个虚成员函数。 std::basic_stringstream&lt;char&gt; 包含一个成员是 std::basic_stringbuf 实例,其构造需要定义虚成员函数。

在包含&lt;sstream&gt; 之后,您定义并在全局命名空间中引入一个通用的operator | 重载。上面| 表达式中的操作数只包含非依赖名称。因此,这个表达式实际上不应该受到operator | 的存在的影响,因为应该在std::basic_stringbuf::seekoff() 的定义中第一次遇到表达式时决定使用哪个运算符函数。但是,(据我所知)Visual C++ 编译器实际上只是将模板函数实例放在翻译单元的末尾。这本身是基于[temp.point]/8 允许的。但是,Visual C++ 过去也将所有名称查找延迟到模板实例化时间,即documented non-standard behavior。如果没有/permissive- 开关,编译器仍将执行此非标准名称查找作为兼容性功能。然后它将找到并尝试使用您的operator |,这比内置运算符更好,因为两个操作数都是枚举类型,并且需要integral promotion。使用/permissive-,编译器将执行正确的两阶段名称查找并正确决定使用内置的| 运算符。

/permissive- 生效时,有一个/Zc:twoPhase- 标志可以显式打开这种非标准行为。因此,您可以通过打开/permissive-/Zc:twoPhase- 并观察到这会像预期的那样带回错误来验证问题实际上是由非标准名称查找引起的……

除此之外,请注意您的 operator | 不返回值,因此如果您最终在任何地方实际使用此运算符函数,您最终会调用未定义的行为……;)

【讨论】:

以上是关于如何以编程方式获取 /permissve- 在 VS2017 Update8.2 中设置的所有编译器标志的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式获取 Android 手机型号,如何在 android 中以编程方式获取设备名称和型号?

以编程方式读取 IIS 7 网站的 TCP 端口

如何以编程方式圆角并设置随机背景颜色

如何在 CUDA 中以编程方式获取卡规格

如何以编程方式获取 Spark UI 信息

如何以编程方式获取“版本代码”和“型号代码”