35

重複の可能性:
タプルを可変個引数テンプレート関数の引数に展開するにはどうすればよいですか?
タプルを「アンパック」して、一致する関数ポインターを呼び出す

C++11 テンプレートで、(おそらくテンプレート) 関数の個々の引数としてタプルを使用する方法はありますか?

例:
この関数があるとしましょう:

void foo(int a, int b)  
{  
}

そして、私はタプルを持っていauto bar = std::make_tuple(1, 2)ます。

それを使用してテンプレートの方法で呼び出すことはできますfoo(1, 2)か?

foo(std::get<0>(bar), std::get<1>(bar))引数の数がわからないテンプレートでこれを実行したいので、単純にというわけではありません。

より完全な例:

template<typename Func, typename... Args>  
void caller(Func func, Args... args)  
{  
    auto argtuple = std::make_tuple(args...);  
    do_stuff_with_tuple(argtuple);  
    func(insert_magic_here(argtuple));  // <-- this is the hard part  
}

1 つの引数で機能するテンプレートを 1 つ作成したり、2 つの引数で機能する別のテンプレートを作成したりしたくないことに注意してください。</p>

4

2 に答える 2

60

次のようなことを試してください:

// implementation details, users never invoke these directly
namespace detail
{
    template <typename F, typename Tuple, bool Done, int Total, int... N>
    struct call_impl
    {
        static void call(F f, Tuple && t)
        {
            call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t));
        }
    };

    template <typename F, typename Tuple, int Total, int... N>
    struct call_impl<F, Tuple, true, Total, N...>
    {
        static void call(F f, Tuple && t)
        {
            f(std::get<N>(std::forward<Tuple>(t))...);
        }
    };
}

// user invokes this
template <typename F, typename Tuple>
void call(F f, Tuple && t)
{
    typedef typename std::decay<Tuple>::type ttype;
    detail::call_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t));
}

例:

#include <cstdio>
int main()
{
    auto t = std::make_tuple("%d, %d, %d\n", 1,2,3);
    call(std::printf, t);
}

いくつかの追加の魔法と を使用するとstd::result_of、おそらく全体が正しい戻り値を返すようにすることもできます。

于 2012-05-26T12:56:56.077 に答える
4

「インデックスタプル」(コンパイル時整数のタプル)を作成してから、インデックスをパラメーターパックとして推測し、パック拡張でそれらを使用しstd::getてタプルを呼び出す別の関数に転送します。

#include <redi/index_tuple.h>

template<typename Func, typename Tuple, unsigned... I>  
  void caller_impl(Func func, Tuple&& t, redi::index_tuple<I...>)  
  {  
    func(std::get<I>(t)...);
  }

template<typename Func, typename... Args>  
  void caller(Func func, Args... args)  
  {  
    auto argtuple = std::make_tuple(args...);  
    do_stuff_with_tuple(argtuple);
    typedef redi::to_index_tuple<Args...> indices;
    caller_impl(func, argtuple, indices());
  }

私の実装index_tuplehttps://gitlab.com/redistd/redistd/blob/master/include/redi/index_tuple.hにあります が、テンプレートエイリアスに依存しているため、コンパイラがサポートしていない場合は、変更する必要がありますC ++ 03スタイルの「templatetypedefs」を使用し、の最後の2行caller

    typedef typename redi::make_index_tuple<sizeof...(Args)>::type indices;
    caller_impl(func, argtuple, indices());

同様のユーティリティがstd::index_sequenceC++14と同様に標準化されました(スタンドアロンのC ++ 11実装についてはindex_seq.hを参照してください)。

于 2012-05-26T15:23:26.693 に答える