2011-10-08 13 views
4

複数のクラスから継承するクラスを作成しようとしています(バリデーションテンプレートで定義されています)。クラスごとに同じパラメータargsを各クラスのコンストラクタにパックします。しかし、クラスのバリデーションテンプレートとargsのパラメータパックの両方をアンパックすることはできないようです。バリデーションテンプレートで定義された各クラスのコンストラクタにargsのパラメータパックを展開する

私はクラスを持っている:コンストラクタで

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

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

とテスト:

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

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

gccがで失敗

どこ__Policies = T1, T2

明確にするために、私は基本的にやろうとしている:

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

が、T1__Policies

任意のアイデアから推定T2と? gccはタイプリストではなく単一のタイプとして__Policiesを扱っているようです。前もって感謝します!


編集:

私はGCC/G ++ 4.4.5を使用していることを明確にすべきです。

ハワードヒナントの提案を行うことでした。

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

しかし、GCC/G ++ 4.4.5で、これはinvalid use of pack expansion expressionを与えます。これはOSX/clangでうまくいきますが、gcc/g ++でこれを行う方法はありますか?

+2

4.4はC++ 11のサポートに関して古くからあり、4.6の可変的なテンプレートサポートでも、特にパラメータパックのアンパックは不完全であることに注意してください。 – PlasmaHH

+1

本当にC++に興味があれば、gcc 4.7(4.8よりも古い)を使用しようとしないでください。 – OneOfOne

+0

また、 '__'または' _ 'で始まる識別子をあなたのコード。これらのパターンは、コンパイラとその標準ライブラリ用に予約されています。新しいバージョンのコンパイラは警告なしに '#define __Args'を導入し、コードを壊すことがあります。 –

答えて

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); 
} 
+0

これはテストしましたか? –

+0

OS X/clangに表示されているものだけをテストしました。 –

+1

奇妙なことに、私はGCC 4.6.1で 'error:pack expansion expressionの無効な使用 'をたくさん取得します。私は自分のようなものを試していたが、成功しなかった。 –

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 

良い出発点です(どの程度の移植性が必要かによって異なります)。

6

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 ]

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdfから私はf(h(args ...) + args ...);は、あなたが得る最も近いstandardese例かもしれないと思います。あなたがやっていればという

注:コンストラクタのパラメータリストの単一引数を引っ張られ、そしてベースのコンストラクタに順に適用されているだろう

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

argsを展開したら、キーは__Policiesに拡張されます。

+0

複数の別々のパラメータパックがあるとどうなりますか? –

+0

パック展開のパターンは、ネストされたパック展開によって展開されていない** ** 1つ以上のパラメータパック**の名前になります。 –

関連する問題