Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange behaviour of default template-argument in a template-template-parameter

Tags:

Consider this C++11 program:

#include <iostream>

template <class A, class B = char> struct Cont {
    Cont () { std::cout << sizeof(B); }
};

template <template<class, class = int> class C, class E> class Wrap1
{
    C<E> ce;
};

template <template<class, class = int> class C, class... E> class Wrap2
{
    C<E...> ce;
};

int main ()
{
    Wrap1<Cont, void> w1;
    Wrap2<Cont, void> w2;
}

When compiled with either gcc or clang, the output is 41.

Is this behaviour according to the standard? Where exactly does the standard specify it (for both Wrap1 and Wrap2)?

This question is inspired in part by this other question.

like image 732
n. 1.8e9-where's-my-share m. Avatar asked Nov 30 '16 22:11

n. 1.8e9-where's-my-share m.


People also ask

Can template parameters have default values?

Just like in case of the function arguments, template parameters can have their default values. All template parameters with a default value have to be declared at the end of the template parameter list.

CAN default arguments be used with the template?

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 { };

Which is correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.

Why do we use :: template template parameter?

8. Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.


1 Answers

In Wrap2 class, parameter pack "class... E" will replace all the parameters specified by "class C" ( include the default "int" parameter), so "Wrap2 w2" will return 1 which is the default parameter of struct Cont.

Parameter pack replaced all the parameters of class C, so the default parameters of C didn't work here.

#include <iostream>
#include <typeinfo>

template <class A=char, class B = short, class C = int> struct MyTest
{
    MyTest ()
    {
        std::cout << sizeof(A) << " " << typeid(A).name() << " ";
        std::cout << sizeof(B) << " " << typeid(B).name() << " ";
        std::cout << sizeof(C) << " " << typeid(C).name() << std::endl;
    }
};

template <template<class = double, class = double, class = double> class D, class E, class... F> class Wrap
{
    D<E> de; // the parameters of D is: E + default parameters of D.
    D<F...> df; // the parameters of D is: F... + default parameters of MyTest, the default parameter of D don't work, it will be replaced by pack F.
};

int main ()
{
    Wrap<MyTest, int, int> w;
}

//g++ 5.4.0
//output:
//4 i 8 d 8 d
//4 i 2 s 4 i
like image 200
Jun Ge Avatar answered Oct 14 '22 22:10

Jun Ge