4

複数のクラス (可変個引数テンプレートで定義) から継承するクラスを作成しようとしています。各クラスについて、引数の同じパラメーター パックを各クラスのコンストラクターに渡します。ただし、クラスの可変個引数テンプレートと引数のパラメーター パックの両方をアンパックできないようです。

私はクラスを持っています:

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 Variadic テンプレート [temp.variadic]

5 パック展開のパターン内に名前が現れるパラメータパックは、そのパック展開によって展開されます。パラメータパックの名前の出現は、最内包パック展開によってのみ展開されます。パック展開のパターンは、ネストされたパック展開によって展開されない 1 つ以上のパラメーター パックを指定する必要があります。パック展開によって展開されるすべてのパラメーター パックには、同じ数の引数が指定されている必要があります。展開されていないパラメーター パックの名前の外観は不適切です。[ 例:

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 '...' ?
        {}
};

コンストラクターのパラメーター リストの 1 つの引数を取得し、それらを基本コンストラクターに順番に適用します。ポイントは、拡大し__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 に答える