Home > Mobile >  Is it possible to define a constructor taking a universal reference with defaulted value?
Is it possible to define a constructor taking a universal reference with defaulted value?

Time:11-25

When I try to define a constructor taking a universal reference with a defaulted value as a parameter like this:

struct S {
    int x; // I know that universal ref is useless for int, but it's here for simplicity

    template<class T>
    S(const T&& arg = 123) : x(std::forward(arg)) { }
    
    // S(const auto&& arg = 123) : x(std::forward(arg)) { }
    // The auto-syntax fails as well, yields similar error
};

int main() {
    S s;
}

I get an error:

<source>:18:7: error: no matching constructor for initialization of 'S'
    S s;
      ^
<source>:10:5: note: candidate template ignored: couldn't infer template argument 'T'
    S(const T&& arg = 123) : x(std::forward(arg)) { }
    ^
<source>:3:8: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
struct S {
       ^
<source>:3:8: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided

Is there a way to do it with a universal reference or do I have to do it in a different way?

CodePudding user response:

You still need to specify a default argument for the template parameter. It will not be deduced from the function parameter's default argument:

template<class T = int>

You also are misusing std::forward. It always requires a type template argument that should be the template parameter used in the forwarding reference named by the argument.

 x(std::forward<T>(arg))

And finally, a const rvalue reference almost never makes sense. In particular it doesn't form a forwarding reference. Remove the const:

S(T&& arg = 123)

Then it should compile. But just declaring an additional overload without parameters might be simpler.


Note: In the above forwarding reference is synonymous with what the question refers to as universal reference. The former is the now technically correct term used in the standard. The latter is older and was popularized in writing before there was an official term.

CodePudding user response:

T is not deduced from default argument, you might default it too:

template<class T = int>
S(T&& arg = 123) : x(std::forward<T>(arg)) {}

Demo

  • Related