In the enlightened age of 2016, with two new standards under our belt since this question was asked and a new one just around the corner, the crucial thing to know is that compilers supporting the C++17 standard will compile your code as-is.
Template-argument deduction for class templates in C++17
Here (courtesy of an edit by Olzhas Zhumabek of the accepted answer) is the paper detailing the relevant changes to the standard.
Addressing concerns from other answers
The current top-rated answer
This answer points out that "copy constructor and operator=
" wouldn't know the correct template specializations.
This is nonsense, because the standard copy-constructor and operator=
only exist for a known template type:
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;
Here, as I noted in the comments, there is no reason for MyClass *pm
to be a legal declaration with or without the new form of inference: MyClass
is not a type (it's a template), so it doesn't make sense to declare a pointer of type MyClass
. Here's one possible way to fix the example:
MyClass m(string("blah blah blah"));
decltype(m) *pm; // uses type inference!
*pm = m;
Here, pm
is already of the correct type, and so the inference is trivial. Moreover, it's impossible to accidentally mix types when calling the copy-constructor:
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
Here, pm
will be a pointer to a copy of m
. Here, MyClass
is being copy-constructed from m
—which is of type MyClass<string>
(and not of the nonexistent type MyClass
). Thus, at the point where pm
's type is inferred, there is sufficient information to know that the template-type of m
, and therefore the template-type of pm
, is string
.
Moreover, the following will always raise a compile error:
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
This is because the declaration of the copy constructor is not templated:
MyClass(const MyClass&);
Here, the copy-constructor argument's template-type matches the template-type of the class overall; i.e., when MyClass<string>
is instantiated, MyClass<string>::MyClass(const MyClass<string>&);
is instantiated with it, and when MyClass<int>
is instantiated, MyClass<int>::MyClass(const MyClass<int>&);
is instantiated. Unless it is explicitly specified or a templatized constructor is declared, there is no reason for the compiler to instantiate MyClass<int>::MyClass(const MyClass<string>&);
, which would obviously be inappropriate.
The answer by Cătălin Pitiș
Pitiș gives an example deducing Variable<int>
and Variable<double>
, then states:
I have the same type name (Variable) in the code for two different types (Variable and Variable). From my subjective point of view, it affects the readability of the code pretty much.
As noted in the previous example, Variable
itself is not a type name, even though the new feature makes it look like one syntactically.
Pitiș then asks what would happen if no constructor is given that would permit the appropriate inference. The answer is that no inference is permitted, because the inference is triggered by the constructor call. Without a constructor-call, there is no inference.
This is similar to asking what version of foo
is deduced here:
template <typename T> foo();
foo();
The answer is that this code is illegal, for the reason stated.
MSalter's answer
This is, as far as I can tell, the only answer to bring up a legitimate concern about the proposed feature.
The example is:
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
The key question is, does the compiler select the type-inferred constructor here or the copy constructor?
Trying the code out, we can see that the copy constructor is selected. To expand on the example:
int num = 3;
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
Variable var4{Variable(num)}; // infering ctor
// Variable var4(Variable(num)); // illegal
I am not sure how the proposal and the new version of the standard specify this; it appears to be determined by "deduction guides," which are a new bit of standardese that I don't yet understand.
The var4
deduction is illegal due to the "most vexing parse" (the statement is parsed as a function declaration). I'm not totally sure why, because that doesn't look like a valid syntax for a function declaration to me.