How to get programatically, options enabled by Visual Studio 2017 compiler flag /permissive-
As per Microsoft Documentation /permissive- flag sets the /Zc compiler options for strict conformance
Now the below code gets compiled on Visual Studio 2017 Update8.2 with only /permissive- compiler flag on , and fails when /permissive- flag is not turned on (on 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;
}
I want to know which compiler flag of /Zc fixed this
The problem occurs without /permissive-
because the compiler will not perform proper two-phase name lookup for templates.
In sstream, line 270 you'll find:
…
constexpr auto _Both = ios_base::in | ios_base::out;
…
as part of the definition of std::basic_stringbuf::seekoff()
which is a virtual member function. std::basic_stringstream<char>
contains a member that is an std::basic_stringbuf
instance, the construction of which requires the definition of the virtual member functions.
After including <sstream>
, you define and introduce into the global namespace a generic operator |
overload. The operands in the |
expression above contain only non-dependent names. Therefore, this expression should actually not be affected by the presence of your operator |
because the decision which operator function to use should happen at the point where the expression is first encountered in the definition of std::basic_stringbuf::seekoff()
. However, (as far as my understanding goes) the Visual C++ compiler will effectively just put template function instances at the end of the translation unit. This in itself is allowed based on [temp.point]/8 . However, Visual C++ used to also delay all name lookup to template instantiation time which is documented non-standard behavior . Without the /permissive-
switch, the compiler will still perform this non-standard name lookup as a compatibility feature. It will then find and try to use your operator |
which is a better match than the built-in operator because both operands are of enumeration type and would require an integral promotion . With /permissive-
, the compiler will perform proper two-phase name lookup and correctly decide to use the built-in |
operator instead.
There is a /Zc:twoPhase-
flag to explicitly turn on this non-standard behavior when /permissive-
is in effect. Thus, you can verify that the problem actually is caused by non-standard name lookup simply by switching on /permissive-
and /Zc:twoPhase-
and observing that this brings back the error as one would expect…
Apart from that, note that your operator |
does not return a value, so if you end up actually using this operator function anywhere, you'll end up invoking undefined behavior… ;)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.