4

我正在尝试创建一个从多个类(由可变参数模板定义)继承的类,并且对于每个类,将相同的 args 参数包传递给每个类的构造函数。但是,似乎我无法解压缩类的可变参数模板和 args 的参数包。

我有一堂课:

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

使用构造函数:

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

并测试:

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

gcc 失败:

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

在哪里__Policies = T1, T2

为了澄清,我本质上是在尝试做:

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

但从T1_ T2___Policies

有任何想法吗?似乎 gcc 将__Policies其视为单一类型而不是类型列表。提前致谢!


编辑:

我应该澄清一下我使用的是 gcc/g++ 4.4.5。

Howard Hinnant 的建议是:

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

但是,对于 gcc/g++ 4.4.5,这给出了invalid use of pack expansion expression. 这在 OSX/clang 中工作很好,但是有没有办法在 gcc/g++ 中做到这一点?

4

3 回答 3

16

...”很像“ typename”。你只需要继续积极地把它洒在周围,直到事情编译好。:-)

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 );
}
于 2011-10-08T01:37:36.777 回答
6

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

14.5.3 可变参数模板 [temp.variadic]

5 名称出现在包扩展模式中的参数包由该包扩展扩展。参数包名称的外观仅由最里面的封闭包扩展扩展。包扩展的模式应命名一个或多个不通过嵌套包扩展扩展的参数包。由包扩展扩展的所有参数包应具有相同数量的指定参数。未扩展的参数包名称的外观是不正确的。[ 例子:

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
}

—结束示例]

我认为这f(h(args ...) + args ...);可能是您将得到的最接近的标准示例。

请注意,如果您已完成:

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

您将提取构造函数参数列表的单个 arg,并将它们应用于基本构造函数。关键是__Policies在你扩展之后再扩展args

于 2011-10-10T17:34:44.273 回答
0

正如上面评论中提到的,gcc 目前对可变参数模板的支持非常薄弱。尤其是在参数包扩展方面。Gcc 4.6 甚至不能将包扩展为固定长度的列表。

以下代码是一种可能的解决方法,它基于一种更复杂的方法来解决我通常使用的那些限制。它只会在来自 svn 的最新 gcc 上编译:

#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 );
}

所有已发布的 gcc 都会对此感到窒息:

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

这可能也可以通过更多的间接来解决,但这应该是一个很好的起点(取决于你想要多少可移植性)。

于 2011-10-10T14:51:44.927 回答