каким-то образом при наличии НЕшаблонного operator|() для конкретного enum
он перестает его видеть если в неймспейсе A добавить шаблонный оператор|() который всегда отключен.
Что-то я торможу. Не понимаю, что происходит при смене #if 1 / #if 0
Поскольку никто более знающий не высказывается, то риску предположить, что дело в следующем:
— компилятор пытается найти operator| в пространстве имен Qt и не находит;
— компилятор пытается найти operator| в пространстве имен A и находит, но он запрещен из-за std::enable_if<false, T>;
— после чего компилятор перестает искать operator| для Qt::ItemFlag и делает неявное преобразование Qt::ItemFlag в int, после чего применяет штатный operator| для int-ов.
Здравствуйте, K13, Вы писали:
K13>код: https://coliru.stacked-crooked.com/a/053394d0fc0b2cdb
K13>каким-то образом при наличии НЕшаблонного operator|() для конкретного enum K13>он перестает его видеть если в неймспейсе A добавить шаблонный оператор|() который всегда отключен.
K13>Что-то я торможу. Не понимаю, что происходит при смене #if 1 / #if 0
P.S. Так устроен поиск имен — компилер находит в namespace A operator | и на этом путешествие по пространствам имен прекращается. После этого выясняется, что найденный operator | не проходит overload resolution благодаря SFINAE фильтру "std::enable_if_t< false, T >", а других подходящих кандитатов на подстановку в этой области видимости нет. Остается последняя возможность — integral promotion of unscoped enumeration type to int с последующим применением встроенного оператора.
Влепи туда вместо своего operator | какой-нибудь другой, совершенно левый, и получишь ту же самую ошибку:
namespace A {
#if 1 // если тут поставить 0 то все компилируется
//using ::operator|;auto operator | (class Absent&, class Absent&);
#endif
} // namespace A
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, reversecode, Вы писали:
R>что любопытно, MSVC до С++17 компилит и не краснеет))
А ты в режиме "/permissive-" попробуй
Он же потому и не краснеет, что до C++17 (включительно) режим по умолчанию — просто "/permissive", а вот начиная с C++20, по умолчанию используется "/permissive-". Но режимы можно попереключать и вручную.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, K13, Вы писали:
K13>код: https://coliru.stacked-crooked.com/a/053394d0fc0b2cdb K13>каким-то образом при наличии НЕшаблонного operator|() для конкретного enum K13>он перестает его видеть если в неймспейсе A добавить шаблонный оператор|() который всегда отключен. K13>Что-то я торможу. Не понимаю, что происходит при смене #if 1 / #if 0
Вот минимизированный пример, иллюстрирующий твою проблему:
#include <iostream>
namespace Qt {
enum E { _0 = 0, _1 = 1, _32 = 32};
} // namespace Qt
Qt::E operator | (Qt::E a, Qt::E b) { return Qt::E(int(a) | int(b)); }
namespace A {
#if 1 // если тут поставить 0 то все компилируется
//using ::operator |; // или если раскомментировать это объявление, то тоже все компилируетсяauto operator | (class XXX&, class YYY&);
#endif
Qt::E foo() { return Qt::_1 | Qt::_32; } // error: invalid conversion from 'int' to 'Qt::E' [-fpermissive]
} // namespace Aint main()
{
std::cout << "foo() = " << (int)A::foo() << std::endl;
}
Начать разбор лучше с конца:
Ошибка компиляции возникает из-за того, что компилятор не может неявно преобразовать целочисленный тип (int) в перечисление (Qt::E);
Целочисленный тип результата возникает из-за того, что компилятр, вместо того, чтобы применить пользовательский оператор битового или (далее просто "оператор"), сначала преобразует операнды к типу int (вы полняет integral promotion), затем применяет к получившимся числам встроенный оператор;
Пользовательский оператор не находится из-за того, что 1) он не может быть найден через ADL; 2) он не может быть найден через unqualified name lookup;
Пользовательский оператор не может быть найден через ADL, потому что он определен не в том же пространстве имен, в которором определен тип его операндов (Qt::E);
Пользовательский оператор не может быть найден через unqualified name lookup из-за того, что при поиске от точки использования в пространстве имен A находится другая версия этого оператора, не подходящая по критериям overload resolution (несовместимый тип операнов или препятствующий фильтр SFINAE — это не важно). После обнаружения данной версии оператора дальнейший поиск кандидата на подстановку прекращается.
Возможные способы решения:
Внести пользовательский оператор в одно пространство имен с перечислением. В этом случае оператор всегда будет рассматриваться как кандидат на подстановку, независимо от наличия других версий оператора в пространсвах имен, где он используется;
Внести пользовательский оператор в пространство имен по месту использования при помощи using declaration. Объявление должно быть видимо во всех точках использования.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>P.S. Так устроен поиск имен — компилер находит в namespace A operator | и на этом путешествие по пространствам имен прекращается.
Вот этого я не знал/забыл. Что поиск кандидатов на перегрузку прекращается.