Armbie
Armbie

Reputation: 197

Template Argument Deduction guide for unique_ptr argument type?

Is it possible to write a deduction guide so that an instance of Simple can be declared without template arguments? I've tried but cannot get the correct form to extract the std::unique_ptr element type.

//------------------------------------------------------------------------------
template< class T >
class Simple
{
public:
    Simple( std::unique_ptr< T >& u ) :
    u_( u )
    {}
private:
    std::unique_ptr< T >& u_;
};

class MyThing
{};

int main()
{
    std::unique_ptr< MyThing > upSimple;
    Simple( upSimple ); // error C2955: 'Simple': use of class template requires template argument list
}

Upvotes: 3

Views: 950

Answers (1)

max66
max66

Reputation: 66200

Is it possible to write a deduction guide so that an instance of Simple can be declared without template arguments? I've tried but cannot get the correct form to extract the std::unique_ptr element type.

The problem is another.

The implicitly generated deduction guides are perfectly able to extract the correct type template parameter for Simple.

As pointed by Rakete1111, this is a sort of "most vexing parse" problem.

Writing

Simple( upSimple );

your intention was to obtain the initialization of a unnamed temporary object of type Simple (Simple<MyThing>, thanks to new C++17 implicitly generated deduction guides) initialized with the object upSimple.

Unfortunately the compiler (visual-c++, but the same with g++ and clang++) interpret it as the declaration of a new variable (observe that parentheses declaring C++ variables are superfluous but perfectly legal; with int (i); you declare a variable i of type int) of name upSimple and type Simple.

This give an error because

(1) upSimple is defined in the preceding line so we have a redeclaration of upSimple

(2) implicitly generated deduction guides are unable, without a constructor argument, to deduce the template argument T for Simple.

To avoid this ambiguity, and obtain the initialization of a Simple<MyThing> object, you can save the value in a variable with

auto s = Simple(upSimple);

or also with

Simple s(upSimple);

so the compiler can't interpret the line as declaration of variable upSimple anymore.

If you really want an unnamed temporary object, you can use uniform initialization (you can use braces instead of parentheses)

//.....V..........V
Simple { upSimple };

that can't be interpreted as variable declaration.

And, yes: also the imposition of the use of new C++17 standard (through /std:c++17 or -std=c++17 or whichever is required from specific compiler) can be useful.

Upvotes: 4

Related Questions