Essa questão pode ser considerada provavelmente teórica, pois não vejo por que eu teria esse design em código real. Tenho duas classes com alguns operadores de conversão:
class B;
class A {
public:
A() = default;
A(B const &);
};
class B {
public:
B() = default;
operator A();
};
A::A(B const &) {};
B::operator A() { return A{}; };
int main() {
[[maybe_unused]] A ad{B{}}; // direct init
[[maybe_unused]] A ac = B{}; // copy init
}
Com gcc somente e com inicialização de cópia somente, recebo este aviso:
aviso: escolhendo 'B::operator A()' em vez de 'A::A(const B&)' [-Wconversion]
aviso: para conversão de 'B' para 'A' [-Wconversion]
nota: porque a sequência de conversão para o argumento é melhor
Não sendo bem versado nas regras de conversão, não entendo se esse aviso é relevante? Se não, como pode ser silenciado (pode ser doloroso com -Werror
)?
NB Adicionando um pouco de traces , observei comportamentos diferentes de acordo com os compiladores e a natureza da inicialização. As sequências de conversão são dependentes da implementação até certo ponto?
(Não é uma resposta 100% confiável, mas não tenho certeza se é possível.)
Parte da complexidade aqui é que sua
operator A()
função não é um membro const . Então temos uma escolha entre uma função de conversão que toma um não-constthis
e um construtor de conversão que toma um constthis
(que é uma combinação um pouco pior neste caso porque seuB
prvalue de entrada é não-const).Raio de Deus:
Se você fizer isso
B::operator A() const
, a maioria dos compiladores chamaráreturn b
ambíguo ( Godbolt ), mas ainda permitiráreturn A(b)
.Este é basicamente o tópico do CWG 2327 ; veja também Preferência do operador de conversão sobre alterações no construtor de cópia de C++14 para C++17? e Chamada para operador de conversão em vez de converter construtor em C++17 durante resolução de sobrecarga .
Quanto ao motivo pelo qual o Clang prefere a função de conversão ao construtor de conversão, não tenho 100% de certeza, mas parece que o bug #89501 do Clang pode estar relacionado. Parece que o comportamento atual simplesmente aconteceu, não necessariamente por design; mas eles não estão planejando mexer nisso até que o CWG 2327 seja resolvido.