私はタプル型を持っています。新しいタプル型を取得するために、要素型を追加したいと考えています。私はそれのようにすることができます
decltype tuple_cat(MyTuple, std::tuple<MyType>())
ただし、ブーストでそれを行う方法はtuple_cat
ありません。boost::tuple
コンパイル時にこれらすべてが必要だと思います。
一般的な説明は次のとおりです。タプルの連結は、リストや配列の連結に似ています。つまり、アルゴリズムは同じです。ここでは、タプルa
とが与えられたときb
に、 の最後の要素a
を の先頭に移動し、が空になるb
まで繰り返すことにしました。a
最初に: 基本構造。次の構造体は、パラメーター パックを保持します。タプルなど、何でもかまいません。
template<typename... T>
struct pack
{
static const unsigned int size = sizeof...(T);
};
パックのサイズはその中に格納されていることに注意してください。必須ではありませんが、説明に便利です。Boost は struct を使用します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;
};
ここで、パックの側面に 1 つの要素を追加する (左または右に追加する) 低レベルの操作を使用する必要があります。ここでは左に追加が選択されていますが、これが唯一の選択肢ではありません。
// 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
は変更されません。代わりに、追加する要素を知るためにインデックスを使用します。n
継承は、と他のタプルの後のすべてのインデックスの連結である「タイプ」 typedef を定義します(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;
};
以上です!ライブの例はこちら.
ここで、タプルの詳細について説明します。boost::tuple も std::tuple も使用していないことに気付きました。これは、ブースト タプルの実装の多くが可変個引数テンプレートにアクセスできないためです。そのため、一定数のテンプレート パラメーターが使用されます (デフォルトは ですboost::tuples::null_type
)。これを可変個引数テンプレートに直接配置するのは頭痛の種であるため、別の抽象化が必要です。
また、C++ 11 を使用できると仮定しました (decltype
質問の を使用)。C++03 で 2 つのタプルを連結することは可能ですが、より反復的で退屈です。
pack
a をタプルに簡単に変換できます: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<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;
連結するMyTuple
にMyType
は、単純な関数を記述できます。
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);