10

クラス型といくつかの引数型によってパラメーター化されたテンプレートがあるとします。これらの型に一致する一連の引数がタプルに格納されます。これらをクラス型のコンストラクターに渡すにはどうすればよいでしょうか?

ほとんどの C++11 コードでは:

template<typename T, typename... Args>
struct foo {
  tuple<Args...> args;
  T gen() { return T(get<0>(args), get<1>(args), ...); }
};

...長さを固定せずにコンストラクター呼び出しでどのように埋めることができますか?

これを行う再帰的なテンプレート呼び出しの複雑なメカニズムを思いつくことができると思いますが、これを最初に望んでいるとは信じられないので、すぐに使用できるソリューションがあると思います、おそらく標準ライブラリでも。

4

6 に答える 6

5

これを実現するには、いくつかのテンプレートメタプログラミング機構が必要です。

引数ディスパッチを実現する最も簡単な方法は、整数のパックされたコンパイル時シーケンスを含む式でパック拡張を利用することです。このようなシーケンスを構築するには、テンプレート機構が必要です(このようなシーケンスを標準化する提案の詳細については、この回答の最後にある注釈も参照してください)。

index_range整数のコンパイル時の範囲[M、N)をカプセル化するクラス(テンプレート)とindex_list整数のコンパイル時のリストをカプセル化するクラス(テンプレート)があるとすると、次のように使用します。

template<typename T, typename... Args>
struct foo
{
    tuple<Args...> args;

    // Allows deducing an index list argument pack
    template<size_t... Is>
    T gen(index_list<Is...> const&)
    {
        return T(get<Is>(args)...); // This is the core of the mechanism
    }

    T gen()
    {
        return gen(
            index_range<0, sizeof...(Args)>() // Builds an index list
            );
    }
};

そして、ここにとの可能な実装がindex_rangeありindex_listます:

//===============================================================================
// META-FUNCTIONS FOR CREATING INDEX LISTS

// The structure that encapsulates index lists
template <size_t... Is>
struct index_list
{
};

// Collects internal details for generating index ranges [MIN, MAX)
namespace detail
{
    // Declare primary template for index range builder
    template <size_t MIN, size_t N, size_t... Is>
    struct range_builder;

    // Base step
    template <size_t MIN, size_t... Is>
    struct range_builder<MIN, MIN, Is...>
    {
        typedef index_list<Is...> type;
    };

    // Induction step
    template <size_t MIN, size_t N, size_t... Is>
    struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
    {
    };
}

// Meta-function that returns a [MIN, MAX) index range
template<unsigned MIN, unsigned MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;

また、クラステンプレートを標準化するという、 Jonathan Wakelyによる興味深い提案が存在することにも注意してください。これは、私がここで呼んだものと非常によく似ています。int_seqindex_list

于 2013-02-15T15:15:31.490 に答える
5

index_sequencea std::tuple(またはstd::pairstd::array、またはタプル インターフェイスをサポートするその他のもの)を展開するために使用します。

#include <utility>
#include <tuple>

template <typename Tuple, std::size_t... Inds>
SomeClass help_make_SomeClass(Tuple&& tuple, std::index_sequence<Inds...>)
{
    return SomeClass(std::get<Inds>(std::forward<Tuple>(tuple))...);
}

template <typename Tuple>
SomeClass make_SomeClass(Tuple&& tuple)
{
    return help_make_SomeClass(std::forward<Tuple>(tuple),
        std::make_index_sequence<std::tuple_size<Tuple>::value>());
}

std::index_sequencestd::make_index_sequenceC++1y になります。それらを定義するヘッダーが見つからない場合は、次を使用できます。

template <std::size_t... Inds>
struct index_sequence {
    static constexpr std::size_t size()
    { return sizeof...(Inds); }
};

template <std::size_t N, std::size_t... Inds>
struct help_index_seq {
    typedef typename help_index_seq<N-1, N-1, Inds...>::type type;
};

template <std::size_t... Inds>
struct help_index_seq<0, Inds...> {
    typedef index_sequence<Inds...> type;
};

template <std::size_t N>
using make_index_sequence = typename help_index_seq<N>::type;

C++11 モードでの実際の例: http://coliru.stacked-crooked.com/a/ed91a67c8363061b

于 2013-12-05T22:41:04.243 に答える
3

C++14 では、次の標準サポートが追加されindex_sequenceます。

template<typename T, typename... Args>
struct foo {
  tuple<Args...> args;
  T gen() { return gen_impl(std::index_sequence_for<Args...>()); }
private:
  template <size_t... Indices>
  T gen_impl(std::index_sequence<Indices...>) { return T(std::get<Indices>(args)...); }
};
于 2014-04-12T03:30:32.817 に答える
1

0からn-1までのインデックスのシーケンスを作成します。

template<size_t... indexes>
struct seq {};

template<size_t n, size_t... indexes>
struct make_seq: make_seq<n-1, n-1, indexes...> {};

template<size_t... indexes>
struct make_seq: make_seq<0, indexes...> {
  typedef seq<indexes...> type;
};

引数と並行して、または場合によってはインデックスとして、それらを解凍しget<>ます。

目標は次のようなものです。

template< typename T, typename Tuple, typename Indexes >
struct repack;

template< typename... Ts, size_t... indexes >
struct repack< tuple<Ts...>, seq<indexes...> > {
  T operator()( tuple<Ts...> const& args ) const {
    return T( get<indexes>(args)... );
  }
};

repackあなたのようにこのように使用してくださいgen

T gen() {
  repack<T, tuple<Args...>, typename make_seq<sizeof...(Args)>::type> repacker;
  return repacker( args );
}    
于 2013-02-15T15:14:56.720 に答える
1

インデックストリックを使用する必要があります。これは、間接参照のレイヤーを意味します。

template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
  : build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};

template<typename T, typename... Args>
struct foo {
  tuple<Args...> args;
  T gen() { return gen(build_indices<sizeof...(Args)>{}); }
private:
  template<std::size_t... Is>
  T gen(indices<Is...>) { return T(get<Is>(args)...); }
};
于 2013-02-15T15:15:57.513 に答える