2010-12-10 6 views
2

私はvariadicクラステンプレートを持っています。これは入れ子になったvariadicクラステンプレートを持っています。外部クラステンプレートには、任意の数の引数を受け入れ、内部型のオブジェクトを返す関数テンプレートがあります。私の問題は、外部型のバリエーションにかかわらず、これらの内部型(および内部型のみ)の任意のバリエーションを受け入れる完全に別個の関数を作成することです。その外側のクラステンプレートのみ。ではない私は十分に...ここで私が働いている何を本質的だと説明したかどうかわから:variadic関数テンプレートは、1つのvariadicクラステンプレートのネストされたvariadicクラステンプレートのバリエーションのみを受け入れるように制限しますか?

template<typename... ArgsOuter> class Outer { 
    typedef Outer<ArgsOuter...> outer_t; 

    template<typename... ArgsInner> class Inner { 
     //static const outer_t* outer; 
     typedef outer_t outer; 

     Inner(const ArgsInner&... args_inner) { 
      //do stuff 
     } 
    }; 

    /* 
     What's passed in here will be related to and will be a subset of 
     the types used to define the Outer class, but I'm not really 
     concerned about checking what's being passed in right now. 
    */ 
    template<typename... ArgsFunc> 
    make_inner(ArgsFunc... args_func) { 
     return Inner<ArgsFunc...> (args_func...); 
    } 
}; 

struct ThingA : Outer<int, int, float> { 
}; 

struct ThingB : Outer<int, string, int> { 
}; 

struct ThingC : Outer<string, string, int, int> { 
}; 

//struct ThingN : Outer<random types...> {} 

//...meanwhile, over at main... 

ThingA tA; 
ThingB tB; 
ThingC tC; 

auto tA_inner = tA.make_inner(1, 1.1); 
auto tB_inner = tB.make_inner(2, "foo"); 
auto tC_inner = tC.make_inner("bar", 2, "foobar"); 

//mystery_func() is the function I'm not sure how to define. 
auto meatloaf = mystery_func(tA_inner, tB_inner, tC_inner); 

誰でもこのためSFINAEまたは可変引数関数テンプレート(または他の)解決策がありますか?

答えて

1

まあ、私は自分の質問に答えるために着手していなかったが、私は、私はこの1つを把握するために、過去数日だけで十分な壁に頭を打つたと思う...と確かに道に沿っていくつかの新しいものを学んだ(そこに苦情はない)。これは少し醜い鴨(SFINAE +タイプの特性のメタ関数+可変関数テンプレート)ですが、私はいくつかの簡単なテストを実行しましたが、期待どおりに動作するようです。

//Use SFINAE to limit the types accepted 
template<typename A, typename Result> 
struct require_1_type { }; 

//Limit to Outer class 
template<typename... ArgsA, typename Result> 
struct require_1_type<Outer<ArgsA...>, Result> { 
    typedef Result type; 
}; 

//Zero argument, base case for variadic function template. 
void mystery_func() {} 

//Recursive portion of variadic function template. 
template<template<typename...> class First, typename... ArgsA, typename... Others> 
typename std::enable_if< 
    std::is_same< 
     First<ArgsA...> 
     , typename require_1_type< 
      typename First<ArgsA...>::outer_t 
      , typename First<ArgsA...>::outer_t::template Inner<ArgsA...> 
     >::type 
    >::value 
    , some_lib::list<First<ArgsA...>, Others...> 
>::type 
mystery_func (First<ArgsA...> first, Others... others) { 
    mystery_func(others...); 
    return some_lib::make_list(first, others...); 
} 
私の目標は、渡されるタイプを、Outerの任意のバリエーションに対してInnerの任意のバリエーションに限定することでした。私はこれが私が探していたことをすると思う、少なくともそれはそう思う。

次のようにどのようにこのすべての作品の私の理解で、適宜修正してください:

Inner一連のオブジェクトが渡されます。各InnerオブジェクトはそのOuterタイプを参照のtypedefがあります。パラメータパックからInnerオブジェクトを1つ取り除いて、 'Outerタイプを参照するtypedefをチェックして、期待されるOuterタイプと一致することを確認します。一致する場合は、渡された最初のInnerオブジェクトで使用されているパラメータパックを取得し、最初のInnerによって参照されるOuterのtypedefを通じて参照するInnerテンプレートにパックを渡します。次に、それらの2つを確認して、同じものであることを確認します。そうであれば、その特定の関数テンプレートインスタンス化が有効になります。

variadic関数テンプレート自体は単に再帰的に呼び出します。パラメータパック内のすべてのオブジェクトは、関数の空のバージョンを呼び出す引数がなくなるまで、同じチェックが実行されます。最後に、各再帰は(この場合)オブジェクトをリストにまとめた関数を呼び出す。

コンパイラがmake_listの呼び出しをすべて無効にしていて、最後のもの(mystery_func()の最初の呼び出しによって行われるものを除く)とその唯一のもの目的の戻り値があります。

とにかく、改善、コメント、単純化が大歓迎です。

+0

返品の種類は素晴らしいです。 – Griwes

2

これは実際には不可能かもしれないと思います。あなたが望むと思われるものは、次のようなことをする能力です:

template < typename ... Args1, typename ... Args2, typename ... Args3> 
?? mystery_func(Inner<Args1...>,Inner<Args2...>,Inner<Args3...>); 

私はそうすることはできません。できるなら、あなたの答えがあります。

私はあなたがそれをすることができるとは思っていないので、代わりに何をしなければならないかは、3種類のタイプを取って、それらがインナー<> sであることをテストするためにSFINAEを使用することです。メタ関数:

template < typename T > is_inner : boost::mpl::false_ {}; 
template < typename ... Pack > is_inner< Inner<Pack...> > : boost::mpl::true_ {}; 
+0

私は、OuterとInnerのインスタンスを1つだけ分離できれば、可変的な関数テンプレートは私がやりたいことを処理できると思っていますが、それらを構築する経験はあまりありません、確かに、この笑いが好きではない)。一方、私はSFINAEがmystery_funcの引数のセット数を処理できることを知っていますが、N個の引数を設定する方法は失われています。 –

+0

私はあなたがおそらくそれを最初のやり方ですることはできないと確信しています。 2番目の方法は簡単です.Argsのパックを受け入れて、is_innerがすべてのものに当てはまることを確認してください。 –

+0

私はこれをさらに深く掘り下げていました。私は解決策があると思います。私がしたことを示す回答を投稿しました。私は正直なところ私自身の質問に答えるために出発しなかったので、私は受け入れられた答えを変えることによって何も意味しません。私はそれが正しい方向(または私が正しい方向であったと思うもの、私の解決策はちょうど迷惑であるかもしれないと思っていたが、それはうまくいくようだ)と思ったので、あなたの答えをupvotedした。 –

関連する問題