将 args 参数包解压到可变参数模板中定义的每个类的构造函数中

发布于 2024-12-08 18:41:11 字数 1324 浏览 0 评论 0 原文

我正在尝试创建一个继承多个类(由可变参数模板定义)的类,并且对于每个类,将相同的 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... ){}
};

但是使用 T1T2__Policies 推导出来

有什么想法吗?看起来 gcc 将 __Policies 视为单一类型而不是类型列表。提前致谢!


编辑:

我应该澄清我正在使用 gcc/g++ 4.4.5。

Howard Hinnant 的建议是:

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

但是,对于 gcc/g++ 4.4.5,这会导致包扩展表达式的使用无效。很高兴这可以在 OSX/clang 中工作,但是有没有办法在 gcc/g++ 中做到这一点?

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++?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

手心的温暖 2024-12-15 18:41:11

...”很像“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 );
}

"..." 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 );
}
§对你不离不弃 2024-12-15 18:41:11

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

14.5.3 可变参数模板                              [温度变量]

5  名称出现在包扩展模式中的参数包将由该包扩展进行扩展。 参数包名称的外观仅由最内层的封闭包扩展来扩展。包扩展的模式应命名一个或多个未由嵌套包扩展扩展的参数包。由包扩展扩展的所有参数包应指定相同数量的参数。未展开的参数包名称的外观格式不正确。 [示例:

模板<类型名称...>结构体元组{};
模板<类型名称 T1,类型名称 T2>结构对{};

模板结构拉链{
  模板结构体带有 {
    typedef Tuple ...>>类型;
  };
};

typedef zip::with::type T1;
    // T1 是 Tuple, Pair>
typedef zip::with::type T2;
    // 错误:为 Args1 和 Args2 指定的参数数量不同

模板<类...参数>无效g(参数...参数){
  f(const_cast(&args)...); // OK:“Args”和“args”被扩展
  f(5 ...); // 错误:模式不包含任何参数包
  f(参数); // 错误:参数包“args”未展开
  f(h(参数 ...) + 参数 ...); // OK:第一个“args”在 h 内扩展,第二个
  // “args” 在 f 中扩展
}

—示例结束]

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

请注意,如果您这样做了:

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

您将提取构造函数参数列表的单个参数,并将它们按顺序应用到基本构造函数。关键是在展开args之后再展开__Policies

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.

早茶月光 2024-12-15 18:41:11

正如上面评论中提到的,目前 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

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

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文