Определенное пользователем неявное преобразование из класса enum при вызове перегруженного оператора не


Рассмотрим следующий пример:

struct ConvertibleStruct {};

enum class ConvertibleEC {};

struct Target {
    // Implicit conversion constructors
    Target(ConvertibleStruct) {}
    Target(ConvertibleEC) {}
};

Target operator~(const Target& t) {
    return t;
}

Target anotherFunction(const Target& t) {
    return t;
}

int main() {
    ConvertibleStruct t;
    ConvertibleEC ec;

    ~t;                   // 1. Works finding the operator overloaded above
    ~ec;                  // 2. Fails to compile on clang 3.4 and gcc 4.8.2
    operator~(ec);        // 3. Works finding the operator overloaded above

    anotherFunction(ec);  // 4. Works
}

Версии компилятора:

Приведенные выше выводы относятся к clang 3.4 и gcc 4.8.2. Тест 2. на самом деле прекрасно компилируется на gcc 4.7.3 с -std=c++11. Возможно, ошибка в ранней реализации GCC C++11?

Утверждения:

  • учитывая, что 1. компиляции, определяемые пользователем неявные преобразования проверяются при вызове оператора ~.
  • учитывая, что 4. компиляции, определяемые пользователем неявные преобразования проверяются на enum class объекты.

Вопросы:

  • являются вышеуказанные утверждения правильные?
  • если они есть, то почему 2. не удается скомпилировать?
  • учитывая, что 2. не удается скомпилировать, почему 3. компилировать?
1 5

1 ответ:

Второй тест, ~ec, наталкивается на особенность поиска имен операторов в выражениях: [over.спичка.опер] / 3 (из "древнего" N3797):

Для унарного оператора @ с операндом типа, cv-безусловная версия которого T1 [...]

Набор кандидатов, не являющихся членами Совета, является результатом неквалифицированного отбора. поиск operator@ в контексте выражения в соответствии с обычные правила поиска имен в неквалифицированных вызовах функций разве что все функции-члены игнорируются. однако, если операнд отсутствует имеет тип класса, только те функции, не являющиеся членами в наборе подстановок которые имеют первый параметр типа T1 или " ссылка на (возможно cv-квалифицированный) T1", Когда T1 является типом перечисления [...] являются функции-кандидаты .

Таким образом, ::operator~(const Target&) не должно быть найдено/использовано с A для выражения с унарным оператором, примененным к операнду типа ConvertibleEC.


Для первого, ~t, операнд относится к типу класса, и указанное выше исключение не применяется.

И в третьем, и в четвертом тесте используется не поиск оператора, а обычный неквалифицированный поиск. Обычный неквалифицированный поиск находит ::operator~(const Target&) (в случаях 1 и 3) и anotherFunction (в случае 4).