Почему явное преобразование bool() не происходит в контекстном преобразовании

Если следующая тестовая программа

#include <iostream>

class A {
public:
    A() {}
    explicit operator bool() const {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return true;
    }
//    explicit operator bool() {
//        std::cout << __PRETTY_FUNCTION__ << std::endl;
//        return true;
//    }
    const operator int() const {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return 1;
    }
    operator int() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        return 1;
    }
};

int main() {
    A a;
    if (a) {
        std::cout << "bool()" << std::endl;
    }
    if (a + 0) {
        std::cout << "int()" << std::endl;
    }
}
Выполняется

выход -

int A::operator int()
bool()
int A::operator int()
int()

а не

bool A::operator _Bool()
bool()
int A::operator int()
int()

что я ожидал (и что вы получите, если разобьете прокомментированные части).

Итак, вопрос в том, каковы правила, дающие преобразование в не-const-int приоритет перед преобразованием в const-bool?

Ответ 1

При выполнении разрешения перегрузки при привязке ссылок предпочтительнее тип cv-qualify. Это обсуждается в 13.3.3.2p3, с приведенным примером:

struct X {
  void f() const;
  void f();
};
void g(const X& a, X b) {
  a.f(); // calls X::f() const
  b.f(); // calls X::f()
}

Обратите внимание, что привязка объекта к неявному параметру объекта функции-члена (13.3.1.1.1p2) является ссылкой (13.3.3.1.4).

Операторы преобразования рассматриваются как функции-члены (13.3.1.5) для целей разрешения перегрузки (13.3p2). Контекстное преобразование в bool имеет семантику инициализации (4p4).

Важно, что любое преобразование, требуемое для возвращаемого типа оператора преобразования, рассматривается только после рассмотрения разрешения перегрузки между самими операторами преобразования (13.3.3p1).

Решение состоит в том, чтобы гарантировать, что все операторы преобразования имеют одинаковую const -qualification, особенно для скалярного типа.

Ответ 2

каковы правила, дающие преобразование в не-const-int приоритет перед преобразованием в const-bool?

Использование функции const-члена не-const-объекта требует преобразования неконстантного объекта в const-объект. Вот почему operator int() имеет лучшее совпадение над operator bool() const.

Чтобы сделать его более понятным, если вы удалите операторы int, то что действительно происходит с первым контекстом bool (first if):

if ( const_cast<const A&>(a).operator bool() ) {

Вместо этого происходит следующее:

if ( a.operator int() )