Проблема возникает без /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 ++ также задерживал весь поиск имен до времени создания шаблона, которое является документированным нестандартным поведением .Без ключа /permissive-
компилятор все равно будет выполнять этот нестандартный поиск имен в качестве функции совместимости.Затем он найдет и попытается использовать ваш operator |
, который лучше соответствует встроенному оператору, поскольку оба операнда имеют тип перечисления и потребуют интегральное повышение .С /permissive-
компилятор выполнит правильный двухфазный поиск имени и правильно решит использовать вместо этого встроенный оператор |
.
Существует флаг /Zc:twoPhase-
дляявно включите это нестандартное поведение, когда действует /permissive-
.Таким образом, вы можете проверить, что проблема на самом деле вызвана нестандартным поиском имени, просто включив /permissive-
и /Zc:twoPhase-
и заметив, что это возвращает ошибку, как и следовало ожидать ...
Кроме этого, обратите внимание, что ваш operator |
не возвращает значение, поэтому, если вы в конечном итоге фактически используете эту функцию оператора, вы в конечном итоге вызовете неопределенное поведение…;)