2013-07-14 10 views

答えて

6

私はこのすべてをコンパイル時に使いたいと思っています。

一般的な説明は以下のとおりです。concateningタプルは、リストまたは配列を連結するのに似ていますが、アルゴリズムは同じです。ここでは、タプルabを指定して、aの最後の要素をbの先頭に移動し、aが空になるまで繰り返します。

最初に:基本構造。次の構造体は、パラメータパックを保持します。

template<typename... T> 
struct pack 
{ 
    static const unsigned int size = sizeof...(T); 
}; 

注パックのサイズは、その中に格納されている:たとえば、タプル何もすることができます。必須ではありませんが、説明には便利です。 Boostは構造体boost::tuples::length<T>::value(もっと冗長です)を使用します。

i番目の位置にある要素にアクセスするために、我々は、boost::tuples::element<n, T>と同様の構造を使用します。今

// Get i-th element of parameter pack 
// AKA 'implementation' 
// Principle: the element i is the first element of the sub-array starting at indice i-1 
template<int n, typename F, typename... T> 
struct element_at : public element_at<n-1, T...> 
{ 
}; 

template<typename F, typename... T> 
struct element_at<0, F, T...> 
{ 
    typedef F type; 
}; 

// Get i-th element of pack 
// AKA 'interface' for the 'pack' structure 
template<int n, typename P> 
struct element 
{ 
}; 

template<int n, typename... T> 
struct element<n, pack<T...>> 
{ 
    typedef typename element_at<n, T...>::type type; 
}; 

は、我々はパックの側に一つの要素を追加して低レベルの操作を使用しなければなりません(左または右に追加)。ここでは左側に追加することが選びましたが、それが唯一の選択肢ではありません。テンプレートの場合

// Concat at left (only for structure 'pack') 
template<typename a, typename b> 
struct tuple_concat_left 
{ 
}; 

template<typename a, typename... b> 
struct tuple_concat_left<a, pack<b...>> 
{ 
    typedef pack<a, b...> type; 
}; 

aは変更されず、代わりに、我々は追加する何の要素を知っているindiceを使用しています。継承は、nと他のタプル(nを含まず、順番に)の後のすべてのインデックスの連結である '型'型定義を定義します。 indice nの要素を左に連結するだけです。

// Concat 2 tuples 
template<typename a, typename b, int n = 0, bool ok = (n < a::size)> 
struct tuple_concat : public tuple_concat<a, b, n+1> 
{ 
    typedef typename tuple_concat_left< 
     typename element<n, a>::type, 
     typename tuple_concat<a, b, n+1>::type 
    >::type type; 
}; 

template<typename a, typename b, int n> 
struct tuple_concat<a, b, n, false> 
{ 
    typedef b type; 
}; 

それだけです! Live example here

タプルの詳細については、私はboost :: tupleもstd :: tupleも使用していないことに気付きました。これは、boost_tupleの実装の多くがバリデーショナルテンプレートにアクセスできないため、固定数のテンプレートパラメータが使用されます(デフォルトはboost::tuples::null_type)。これを可変的なテンプレートに直接置くことは頭痛であり、したがって別の抽象化が必要です。

私はまたあなたの質問でdecltypeとC++ 11を使用できると仮定しました。 C++で2つのタプルを連結することは可能ですが、繰り返しと退屈です。

あなたは本当に簡単にタプルにpackを変換することができます:ちょうどにpack定義を変更します。

template<typename... T> 
struct pack 
{ 
    static const unsigned int size = sizeof...(T); 
    typedef boost::tuple<T...> to_tuple; // < convert this pack to a boost::tuple 
}; 
1

C++ 14には、コンパイル型で整数のシーケンスを生成するためのライブラリを提供しています。これは、タプルや配列(example)のような静的シーケンスを操作するのに役立ちます。

template<typename X, typename Tuple, size_t... Ints> 
auto concat(X x, Tuple t, integer_sequence<Ints...>) 
    -> decltype(std::make_tuple(x, std::get<Ints>(t)...)) 
{ 
    return std::make_tuple(x, std::get<Ints>(t)...); 
} 

template<typename X, typename... T> 
std::tuple<X, T...> concat(X x, std::tuple<T...> t) 
{ 
    return concat(x, t, index_sequence_for<T...>()); 
} 

concat(MyType, MyTuple); 
: 整数列が MyType MyTupleをCONCATするに

template<size_t... Ints> 
struct integer_sequence {}; 

template<size_t Size, size_t... Ints> 
struct implementation : implementation<Size-1, Size-1, Ints...> {}; 

template<size_t... Ints> 
struct implementation<0, Ints...> 
{ 
    typedef integer_sequence<Ints...> type; 
}; 

template<class... T> 
using index_sequence_for = typename implementation<sizeof...(T)>::type; 

を得ることができ、あなたは単純な関数を書くことができます

関連する問題