Почему явное преобразование 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() )