Este é o cerne de um problema do Tensorflow .
Considere o seguinte código:
class Option;
class Base
{
public:
explicit Base(Option opt);
};
class Derived : public Base
{
public:
using Base::Base;
explicit Derived(const Option &opt);
};
Derived
doit(const Option &opt)
{
return Derived(opt);
}
Quando compilado com versões do GCC até 14.2, ele falha assim:
<source>: In function 'Derived doit(const Option&)':
<source>:19:21: error: call of overloaded 'Derived(const Option&)' is ambiguous
19 | return Derived(opt);
| ^
<source>:6:12: note: candidate: 'Base::Base(Option)'
6 | explicit Base(Option opt);
| ^~~~
<source>:12:15: note: inherited here
12 | using Base::Base;
| ^~~~
<source>:13:12: note: candidate: 'Derived::Derived(const Option&)'
13 | explicit Derived(const Option &opt);
| ^~~~~~~
<source>:9:7: note: candidate: 'constexpr Derived::Derived(const Derived&)'
9 | class Derived : public Base
| ^~~~~~~
<source>:9:7: note: candidate: 'constexpr Derived::Derived(Derived&&)'
Compiler returned: 1
O Clang aceita esse código sem reclamar.
Isso parece ser um bug no Clang (por permitir uma chamada ambígua) ou no GCC (por não permitir uma chamada não ambígua). Mas não tenho certeza de qual. Então, essa chamada é ambígua ou não?
A inicialização é ambígua e clang++ está incorreto.
Uma regra que quase se aplica é [over.match.best] p7 : Na resolução de sobrecarga, uma função viável
F1
é melhor do que uma função viávelF2
seMas como os tipos de parâmetro
Option
econst Option&
são diferentes, essa regra deve ser ignorada. Nenhuma outra regra na conversão de sobrecarga distingue entre um construtor herdado e um construtor de membro simples. As sequências de conversão implícitas de umconst Option
lvalue para um tipo de parâmetroOption
ou para um tipo de parâmetroconst Option&
são ambíguas, portantoDerived(opt)
, malformadas.Isso já foi registrado como um bug do LLVM . Aparentemente, uma correção proposta está sendo movida ativamente.
Não é uma resposta real:
O mesmo erro ocorre para códigos como:
Aos meus olhos, há claramente uma sobrecarga melhor - que é a versão const ref. Então, vejo por que o clang não reclama. Por outro lado, ambas as opções são viáveis.
Por outro lado, não vejo razão para haver uma versão por valor e uma versão por const-ref...
Se você quiser manipular temporários de forma diferente, você pode usar `&&`, por exemplo: