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?
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.
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.)
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>
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.
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.
@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);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With