Na era iluminada de 2016, com dois novos padrões em nosso currículo desde que essa pergunta foi feita e um novo chegando, o crucial é saber que os compiladores que suportam o padrão C ++ 17 compilarão seu código como está .
Dedução de argumento de modelo para modelos de classe em C ++ 17
Aqui (cortesia de uma edição de Olzhas Zhumabek da resposta aceita) está o artigo detalhando as mudanças relevantes no padrão.
Lidando com as preocupações de outras respostas
A resposta com melhor classificação atual
Esta resposta indica que "construtor de cópia e operator=
" não saberia as especializações de modelo corretas.
Isso é um absurdo, porque o construtor de cópia padrão operator=
existe apenas para um tipo de modelo conhecido :
template <typename T>
class MyClass {
MyClass(const MyClass&) =default;
... etc...
};
// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm; // WHAT IS THIS?
*pm = m;
Aqui, como observei nos comentários, não há razão para MyClass *pm
ser uma declaração legal com ou sem a nova forma de inferência: MyClass
não é um tipo (é um modelo), portanto, não faz sentido declarar um ponteiro de tipo MyClass
. Esta é uma maneira possível de corrigir o exemplo:
MyClass m(string("blah blah blah"));
decltype(m) *pm; // uses type inference!
*pm = m;
Aqui, jápm
é do tipo correto e, portanto, a inferência é trivial. Além disso, é impossível misturar tipos acidentalmente ao chamar o construtor de cópia:
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
Aqui, pm
haverá um ponteiro para uma cópia de m
. Aqui, MyClass
está sendo construído a partir de m
- que é do tipo MyClass<string>
(e não do tipo inexistente MyClass
). Assim, no ponto em que pm
's tipo é inferido, não é suficiente informação para saber que o tipo de molde m
, e portanto, o tipo de modelo de pm
, é string
.
Além disso, o seguinte sempre gerará um erro de compilação :
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
Isso ocorre porque a declaração do construtor de cópia não é modelada:
MyClass(const MyClass&);
Aqui, o tipo de modelo do argumento do construtor de cópia corresponde ao tipo de modelo da classe geral; isto é, quando MyClass<string>
é instanciado, MyClass<string>::MyClass(const MyClass<string>&);
é instanciado com ele, e quando MyClass<int>
é instanciado, MyClass<int>::MyClass(const MyClass<int>&);
é instanciado. A menos que seja explicitamente especificado ou um construtor com modelo seja declarado, não há razão para o compilador instanciar MyClass<int>::MyClass(const MyClass<string>&);
, o que obviamente seria inapropriado.
A resposta de Cătălin Pitiș
Pitiș dá um exemplo deduzindo Variable<int>
e Variable<double>
, em seguida, afirma:
Eu tenho o mesmo nome de tipo (Variável) no código para dois tipos diferentes (Variável e Variável). Do meu ponto de vista subjetivo, isso afeta muito a legibilidade do código.
Conforme observado no exemplo anterior, Variable
ele próprio não é um nome de tipo, embora o novo recurso faça com que ele se pareça sintaticamente.
Pitiș então pergunta o que aconteceria se nenhum construtor fosse fornecido que permitiria a inferência apropriada. A resposta é que nenhuma inferência é permitida, porque a inferência é disparada pela chamada do construtor . Sem uma chamada de construtor, não há inferência .
Isso é semelhante a perguntar qual versão de foo
é deduzida aqui:
template <typename T> foo();
foo();
A resposta é que esse código é ilegal, pelo motivo declarado.
Resposta de MSalter
Esta é, pelo que eu posso dizer, a única resposta que levanta uma preocupação legítima sobre o recurso proposto.
O exemplo é:
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
A questão principal é: o compilador seleciona o construtor inferido por tipo aqui ou o construtor de cópia ?
Experimentando o código, podemos ver que o construtor de cópia está selecionado. Para expandir o exemplo :
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
// Variable var4(Variable(num)); // compiler error
Não tenho certeza de como a proposta e a nova versão da norma especificam isso; parece ser determinado por "guias de dedução", que são um novo padrão de linguagem que ainda não entendo.
Também não sei por que a var4
dedução é ilegal; o erro do compilador de g ++ parece indicar que a instrução está sendo analisada como uma declaração de função.