私はタプル型です。新しいタプル型を取得するために、その中に要素型を追加したいと思います。私は古いタプル型とブースト型の新しいタプル型を作成する方法は?
decltype tuple_cat(MyTuple, std::tuple<MyType>())
のようにそれを行うことができますしかし、私はブーストでそれを行う方法を、boost::tuple
でtuple_cat
を見つけませんか?
私はタプル型です。新しいタプル型を取得するために、その中に要素型を追加したいと思います。私は古いタプル型とブースト型の新しいタプル型を作成する方法は?
decltype tuple_cat(MyTuple, std::tuple<MyType>())
のようにそれを行うことができますしかし、私はブーストでそれを行う方法を、boost::tuple
でtuple_cat
を見つけませんか?
私はこのすべてをコンパイル時に使いたいと思っています。
一般的な説明は以下のとおりです。concateningタプルは、リストまたは配列を連結するのに似ていますが、アルゴリズムは同じです。ここでは、タプルa
とb
を指定して、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
};
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;
を得ることができ、あなたは単純な関数を書くことができます