开发者

Unpacking parameter pack of args into the constructor of each class defined in a variadic template

I'm trying to create a class that inherits from multiple classes (as defined by a variadic template) and, for each class, passes the same parameter pack of args to the constructor of each class. However, it seems as though I'm not able to unpack both the variadic template of classes and the parameter pack of args.

I have a class:

template<class... __Policies>
class GenericPolicyAdapter : public __Policies...{

With constructor:

template<class... __Args>
GenericPolicyAdapter( __Args... args ) : __Policies( args... ){

and test:

GenericPolicyAdapter<T1,T2> generic_policy_adapter( arg1, arg2, arg3 );

gcc fails with:

error: type ‘__Policies’ is not a direct base of ‘GenericPolicyAdapter<T1,T2>’

where __Policies = T1, T2

To clarify, I'm essentially trying to do:

GenericPolicyAdapter : public T1, public T2
{
  public:
    template<class... __Args>
    GenericPolicyAdapter( __Args... args ) : T1( args... ), T2( args... ){}
};

but with T1 and T2 deduced from __Policies

Any ideas? It seems like gcc is treating __Policies as a single type rather than a list of types. Thanks in advance!


Edit:

I should clarify that I'm using gcc/g++ 4.4.5.

The suggestion by Howard Hinnant was to do:

template<class... __Args>
    GenericPolicyAdapter( __Args... args )
        : __Policies( args...)...
    {}

However, with gcc/g++ 4.4.5, this gives invalid use of pack expansion expression. It's great that this works in OSX/clang but is there a way 开发者_如何转开发to do this in gcc/g++?


"..." is a lot like "typename". You just have to keep aggressively sprinkling it around until things compile. :-)

template<class... __Policies>
class GenericPolicyAdapter
    : public __Policies...
{
public:
    template<class... __Args>
        GenericPolicyAdapter( __Args... args )
            : __Policies( args...)...
        {}
};

struct T1
{
    T1(int, int, int) {}
};

struct T2
{
    T2(int, int, int) {}
};

int main()
{
    GenericPolicyAdapter<T1,T2> generic_policy_adapter( 1, 2, 3 );
}


From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

14.5.3 Variadic templates                                 [temp.variadic]

5     A parameter pack whose name appears within the pattern of a pack expansion is expanded by that pack expansion. An appearance of the name of a parameter pack is only expanded by the innermost enclosing pack expansion. The pattern of a pack expansion shall name one or more parameter packs that are not expanded by a nested pack expansion. All of the parameter packs expanded by a pack expansion shall have the same number of arguments specified. An appearance of a name of a parameter pack that is not expanded is ill-formed. [ Example:

template<typename...> struct Tuple {};
template<typename T1, typename T2> struct Pair {};

template<class ... Args1> struct zip {
  template<class ... Args2> struct with {
    typedef Tuple<Pair<Args1, Args2> ... > type;
  };
};

typedef zip<short, int>::with<unsigned short, unsigned>::type T1;
    // T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned>>
typedef zip<short>::with<unsigned short, unsigned>::type T2;
    // error: different number of arguments specified for Args1 and Args2

template<class ... Args> void g(Args ... args) {
  f(const_cast<const Args*>(&args)...); // OK: “Args” and “args” are expanded
  f(5 ...); // error: pattern does not contain any parameter packs
  f(args); // error: parameter pack “args” is not expanded
  f(h(args ...) + args ...); // OK: first “args” expanded within h, second
  // “args” expanded within f
}

—end example ]

I think that f(h(args ...) + args ...); might be the closest standardese example you will get.

Note that if you had done:

template<class... __Policies>
class GenericPolicyAdapter
    : public __Policies...
{
public:
    template<class... __Args>
        GenericPolicyAdapter( __Args... args )
            : __Policies(args)... // See the missing '...' ?
        {}
};

You would have pulled a single arg of the constructor parameter list, and applied them in order to the base constructors. The key is to expand __Policies after you expand args.


As mentioned above in a comment, gcc is pretty weak on variadic template support to day. Especially when it comes to parameter pack expansions. Gcc 4.6 can not even expand packs into fixed length lists.

The following code is a possible workaround that is based on a far more complex way of working around those limitations that I usually use. It will only compile on a very recent gcc from svn:

#include <iostream>

template<class T>
struct derive : T
{
    template<class... A>
    derive( A... a ) :
        T(a...)
    {
    }
};

template<class X, class... T>
struct deriver;

template<class X>
struct deriver<X> :
    derive<X>
{
    template<class... A>
    deriver( A... a ) :
        derive<X>(a...)
    {
    }
};

template<class X, class... T>
struct deriver : 
    derive<X>, deriver<T...>
{
    template<class... A>
    deriver( A... a ) :
        derive<X>(a...), deriver<T...>(a...)
    {
    }
};

template<class... __Policies>
class GenericPolicyAdapter
    : public deriver<__Policies...>
{
public:
    template<class... __Args>
        GenericPolicyAdapter( __Args... args )
            : deriver<__Policies...>( args...)
        {}
};

#define BARK std::cout << __PRETTY_FUNCTION__ << "\n"
struct T1
{
    T1(int, int, int) {BARK;}
};

struct T2
{
    T2(int, int, int) {BARK;}
};

int main()
{
    GenericPolicyAdapter<T1,T2> generic_policy_adapter( 1, 2, 3 );
}

All released gccs will choke on this with:

sorry, unimplemented: cannot expand 'T ...' into a fixed-length argument list

which can possibly also worked around by even more indirection, but this should be a good starting point (depending on how much portability you want).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜