Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't auto be used as a template type parameter?

I've been playing around with C++0x's auto keyword and tried the following.

std::unique_ptr<auto> ptr(new int(0));

I tried compiling it with g++ 4.4.5 and got

error: invalid use of auto

Judging by eye, auto can easily be inferred to int.

My guess is the type inference and the template engine don't talk to each other. Otherwise, the template engine would know to instantiate the template class with int as the type parameter.

Another guess is from the standard, I see this.

A member shall not be declared with auto, extern or register storage class.

But I thought that was the auto as in local variables, not as in auto used to deduce types.

And my last guess is that the compiler thinks this is an auto storage class, not auto for type deduction.

Is there a reason behind this stated in the standard?

like image 370
Russell Avatar asked Jul 27 '11 20:07

Russell


People also ask

Which parameter is allowed for non-type template?

Which parameter is legal for non-type template? Explanation: The following are legal for non-type template parameters:integral or enumeration type, Pointer to object or pointer to function, Reference to object or reference to function, Pointer to member.

What can be a template parameter?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

What is auto template?

An auto keyword in a template parameter can be used to indicate a non-type parameter the type of which is deduced at the point of instantiation. It helps to think of this as a more convenient way of writing: template <typename Type, Type value>

What is template type parameter?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


2 Answers

That's because it has to determine the class on which to call a constructor before determining what to do with its arguments. If you make the constructor a template, it'll just work like any other template function - auto-deducing arguments.

like image 126
dascandy Avatar answered Oct 27 '22 00:10

dascandy


@dascandy has correctly identified what's wrong with your code. I'll try to provide some rationale:

You're expecting the compiler to infer unique_ptr<int> because the argument is an int*, and unique_ptr<int> has a constructor which accepts int*. For a moment let's ignore the fact that we're using std::unique_ptr, and just talk about a template class we wrote (and can specialize).

Why should the compiler infer unique_ptr<int>? The argument isn't int, it's int*. Why shouldn't it guess unique_ptr<int*>? Of course that would result in a compiler error, since unique_ptr<int*>'s constructor won't accept an int*. Unless I add a specialization:

template<>
class unique_ptr<int*>
{
public:
    unique_ptr(int*) {}
};

Now unique_ptr<int*> would compile. How should the compiler know which to choose, unique_ptr<int> or unique_ptr<int*>? What if I add another specialization?

template<>
class unique_ptr<double>
{
public:
    unique_ptr(int*) {}
};

The compiler now has three options to choose from, and it has to instantiate the template with every possible argument in order to find them. Clearly this is not feasible, especially with multiple template arguments and template recursion.

What you can do, is make a factory function which connects the inferred type to exactly one template instance:

template<typename T>
std::unique_ptr<T> make_unique(T* arg) { return arg; }

(of course, this won't work because unique_ptr cannot be copied. But the idea is valid, and used in e.g.make_shared and make_pair.)


Some examples of extreme ugliness:

One could argue that unique_ptr<shared_ptr<int>> is a valid match for this code.

Or how about:

template<typename T>
class unique_ptr
{
public:
    explicit unique_ptr(T* arg);
    unique_ptr(int*, enable_if<(sizeof(T) > 16)>::type* = 0);
};
like image 27
Ben Voigt Avatar answered Oct 27 '22 00:10

Ben Voigt