Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class template argument deduction and default template parameters

The following stripped down code doesn't work with the latest clang++5 but is accepted by g++7:

template<typename Wrapped, typename U>
struct wrapper;

template<typename Wrapped, typename U=int>
struct wrapper
{
    wrapper() = default;

    // Automatic deduction guide
    constexpr explicit wrapper(Wrapped) noexcept {}
};

int main()
{
    struct {} dummy;
    constexpr auto wrapped = wrapper(dummy);
}

It fails with the following error messages:

<source>:18:30: error: no viable constructor or deduction guide for deduction of template arguments of 'wrapper'
    constexpr auto wrapped = wrapper(dummy);
                             ^
<source>:12:24: note: candidate template ignored: couldn't infer template argument 'U'
    constexpr explicit wrapper(Wrapped) noexcept {}
                       ^
<source>:4:8: note: candidate template ignored: could not match 'wrapper<Wrapped, U>' against '(anonymous struct at <source>:17:5)'
struct wrapper;
       ^
<source>:9:5: note: candidate function template not viable: requires 0 arguments, but 1 was provided
    wrapper() = default;
    ^

However if I move the default template parameter =int from the class template definition to the forward declaration, everything works perfectly (U being deduced to int as expected), as if only the default template parameter in the forward declaration was taken into account when create the set of fictional function templates used by deduction guides.

I tried to read the standard wording but couldn't get much out of it for this specific case. Is only taking the default template parameter in the forward declaration the intended behaviour when generating the fictional function templates, or is this a compiler bug?

like image 901
Morwenn Avatar asked Mar 05 '18 09:03

Morwenn


People also ask

What is template argument deduction?

Template argument deduction is used when selecting user-defined conversion function template arguments. A is the type that is required as the result of the conversion. P is the return type of the conversion function template.

Can template have default parameters?

You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };

CAN default arguments be used with the template class?

Can default arguments be used with the template class? Explanation: The template class can use default arguments.

What is a template template parameter in C++?

In C++ this can be achieved using template parameters. 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.


1 Answers

This is not a quote of the Standard per se1, but I feel confident enough to consider it an answer.

According to cppreference, on Default template arguments:

Default template arguments that appear in the declarations and the definition are merged similarly to default function arguments:

template<typename T1, typename T2 = int> class A;
template<typename T1 = int, typename T2> class A;
// the above is the same as the following:
template<typename T1 = int, typename T2 = int> class A;

But the same parameter cannot be given default arguments twice in the same scope

template<typename T = int> class X;
template<typename T = int> class X {}; // error

This implies an implicit rule: A template type argument can be given a default type in the template declaration or template definition interchangeably.

The behavior clang++5 exhibits is definitly a bug.


1) Provided by user Oliv:

[temp.param]/10

The set of default template-arguments available for use is obtained by merging the default arguments from all prior declarations of the template in the same way default function arguments are ([dcl.fct.default]). [ Example:

template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;

is equivalent to

template<class T1 = int, class T2 = int> class A;

 — end example ]

like image 79
YSC Avatar answered Sep 22 '22 09:09

YSC