Why can't constructors deduce template arguments? [duplicate]

Solution 1:

Because nobody has specified how exactly that works. There is a current proposal to the standard committee to make it work. It also lists some of the difficulties:

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4471.html

Update: Here's the newest version of the proposal:

http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0091r0.html

Solution 2:

TL;DR: Template specialization


They can, but only template arguments on the function itself, not on the type.

The declaration Foo f(0); is illegal, because there is no type named Foo. Perhaps you were thinking of

auto f = Foo(0);

but that is not allowed either, because the compiler doesn't know what scope to search in (there are infinite potential types with a constructor named Foo and, with specialization, possibly more than one with a constructor Foo(int))

The usual method to do this is with a factory helper function:

auto f = make_foo(0);

where the factory function's return type depends on type deduction of its parameters.


You can imagine that the factory functions could be automatically generated in namespace scope and then the usual function overloading rules applied, but this runs into significant difficulty because there can be template arguments on both the type and the constructor itself. These could simply be concatenated, with the limitation that this would exclude class templates with variadic argument lists, because there would be no way to distinguish where the type parameters end and the function parameters begin.

Solution 3:

Foo is a class template, not a class. Its type always needs to be supplied in some way or another for a class to be generated with the correct types. You can't do Foo because Foo isn't a type, but Foo<int> is. It creates a class like this:

class Foo {
public:
  Foo( int t ) { }
};

If you only supplied Foo, the compiler wouldn't know how to generate the class. Foo<int> f(0) works because Foo<int> generates the class, substituting T with int. By the type you call the constructor, the compiler already knows that the constructor is accepting an int.

Solution 4:

The name of the class you want to instantiate is Foo<int> (as you indicate).

It is also possible to write Foo<short> f(0), or Foo<unsigned long> f(0), or Foo<Foo<double>*> f(0). In those cases, however, you don't expect the compiler to be able to guess the type if you write only Foo f(0).

One could imagine that a C++ could have been specified with rules to make some such guesses in certain ways (such as, the literal 0 implies type parameter int and no other), but then the language would be even more complicated than it is now and there would be additional ways for people to make programming errors. Actually writing what you mean in a declaration like this seems like not too much to ask.

Edit: After posting this, I noticed in another answer that there is a proposal to make such a feature of C++, indeed as one could imagine.