Domanda

Consider the following snippet:

template<template<class> class T,class U>
struct apply
{
     typedef T<U> type;
};

typedef apply<std::tuple,int>::type tuple_of_one_int; //Should be std::tuple<int>

GCC 4.8.2. says:

type/value mismatch at argument 1 in template parameter list for [...] struct apply
expected a template of type ‘template<class> class T’, got ‘template<class ...> class std::tuple’

Which basically means that a variadic template like std::tuple is not a valid template argument for T in apply.

Is this a GCC bug or does the standard mandates this behaviour?

È stato utile?

Soluzione

Someone correct me if I'm wrong but it seems like it's correct from this quote:

3 A template-argument matches a template template-parameter (call it P) when each of the template parameters in the template-parameter-list of the template-argument’s corresponding class template or [FI 11] template aliasalias template (call it A) matches the corresponding template parameter in the template-parameter-list of P

A (the given template) has to match each of it's templates parameters to P's the template template.

From the second part of the section we learn the restriction doesn't apply in the reverse, meaning a template template containing a parameter pack can match anything.

When P’s template-parameter-list contains a template parameter pack (14.5.3), the template parameter pack will match zero or more template parameters or template parameter packs in the template-parameter- list of A with the same type and form as the template parameter pack in P

As you probably already knew the way to make it work is

template<template<class> class T,class U>                                       
struct apply                                                                       
{                                                                                  
         typedef T<U> type;                                                        
};                                                                                 

template<class T> using tuple_type  = std::tuple<T>;
typedef apply<tuple_type,int>::type tuple_of_one_int;                          

The c++11 standard also has an equivalent example to yours.

template <class ... Types> class C { /∗ ... ∗/ };

template<template<class> class P> class X { /∗ ... ∗/ };

X<C> xc; //ill-formed: a template parameter pack does not match a template parameter  

The last comment completely describes your situation, class C would be the equivalent of std::tuple in this case.

Altri suggerimenti

Your code is ill-formed, there is equivalent example in the standard (under 14.3.3/2):

...
template <class ... Types> class C { /∗ ... ∗/ };

template<template<class> class P> class X { /∗ ... ∗/ };
...
X<C> xc; // ill-formed: a template parameter pack does not match a template parameter
...

The fix:

template<template<class...> class T,class U>
struct apply
{
     typedef T<U> type;
};

typedef apply<std::tuple,int>::type tuple_of_one_int;
typedef apply<std::vector,int>::type vector_of_int;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top