如何以编程方式获取由Visual Studio 2017编译器标志/ permissive-
启用的选项根据Microsoft文档/ permissive-标志设置/ Zc编译器选项以实现严格一致性
现在下面的代码在仅启用/ permissive-编译器标志的Visual Studio 2017 Update8.2上进行编译,并且在未启用/ 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的哪个编译器标志已修复
答案 0 :(得分:0)
在没有/permissive-
的情况下会发生此问题,因为编译器将不会对模板执行正确的两阶段名称查找。
在sstream的第270行中,您将找到:
…
constexpr auto _Both = ios_base::in | ios_base::out;
…
作为std::basic_stringbuf::seekoff()
定义的一部分,该定义是一个虚拟成员函数。 std::basic_stringstream<char>
包含一个成员,该成员是一个std::basic_stringbuf
实例,其构造需要定义虚拟成员函数。
在包含<sstream>
之后,您将定义通用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 |
不会返回任何值,因此,如果最终在任何地方实际使用此运算符,都会导致调用未定义的行为…;)