Considere o seguinte código .
struct any
{
template <typename T>
operator T &&() const;
template <typename T>
operator T &() const;
};
int main()
{
int a = any{};
}
Aqui, o segundo operador de conversão é escolhido pela resolução de sobrecarga. Por quê?
Tanto quanto eu entendo, os dois operadores são deduzidos operator int &&() const
e operator int &() const
respectivamente. Ambos estão no conjunto de funções viáveis. Ler através do [over.match.best] não me ajudou a descobrir por que o último é melhor.
Por que a última função é melhor que a anterior?
template <typename T> operator T &&() const &&; template <typename T> operator T &() const &;
consegue chamar o primeiro.Respostas:
O operador de conversão que retorna
T&
é o preferido porque é mais especializado que o operador de conversão que retornaT&&
.Veja C ++ 17 [temp.deduct.partial] / (3.2):
e / 9:
fonte
Os operadores de conversão de valor de retorno deduzido são um pouco estranhos. Mas a ideia central é que ele funcione como um parâmetro de função para escolher qual deles é usado.
E ao decidir entre
T&&
eT&
asT&
vitórias nas regras de resolução de sobrecarga. Isso é para permitir:trabalhar.
T&&
pode corresponder a um lvalue, mas quando as sobrecargas de referência lvalue e universal estão disponíveis, o lvalue é o preferido.O conjunto certo de operadores de conversão é provavelmente:
ou mesmo
para impedir que a extensão da vida útil com falha o morda.
[RECORTE]
O que acaba dependendo das regras "mais especializadas" ao selecionar sobrecargas:
Portanto,
operator T&&
não é pelo menos tão especializado quantooperator T&
, enquanto nenhum estado de regraoperator T&
não é pelo menos tão especializado quantooperator T&&
, portanto,operator T&
é mais especializado queoperator T&&
.Modelos mais especializados ganham menos que a resolução de sobrecarga, sendo tudo o resto igual.
fonte
&&
vs&
é tratado ao escolher sobrecargas de modelo, mas exibir o texto exato levaria um tempo .Estamos tentando inicializar um
int
de umany
. O processo para isso:Descobrir todo o caminho que podemos fazer isso. Ou seja, determine todos os nossos candidatos. Elas vêm das funções de conversão não explícitas que podem ser convertidas em
int
uma sequência de conversão padrão ( [over.match.conv] ). A seção contém esta frase:Escolha o melhor candidato.
Após o passo 1, temos dois candidatos.
operator int&() const
eoperator int&&() const
, ambos considerados como tendo comoint
finalidade a seleção de funções candidatas. Qual é o melhor candidato a renderint
?Nós temos um desempatador que prefere referências lvalue a referências rvalue ( [over.ics.rank] / 3.2.2 ). No entanto, não estamos vinculando uma referência aqui, e o exemplo é um pouco invertido - é o caso em que o parâmetro é uma referência lvalue vs rvalue.
Se isso não se aplicar, passamos ao desempate [over.match.best] /2.5 de preferir o modelo de função mais especializado.
De um modo geral, a regra geral é que a conversão mais específica é a melhor correspondência. A função de conversão de referência lvalue é mais específica que a função de conversão de referência de encaminhamento, portanto é preferível. Não há nada na
int
inicialização que exija um rvalue (se estivéssemos inicializando umint&&
, então ooperator T&() const
não seria um candidato).fonte
T&&
vitórias não é? Ah, mas não temos um valor a ser vinculado. Ou nós? Ao escolher nossos candidatos, algumas palavras devem ter definido como chegamosint&
eint&&
isso foi obrigatório?