2013-03-21 10 views
14

としてパラメータパックを格納することです:C++、これはデザインのサンプルコードはどのようにトラブルパラメータパックを保存しようとしているが生じています現時点では、変数

template<typename Func, typename... Args> 
void handleFunc(Func func, Args&&... args) { 
    struct nest { 
     Func nestFunc; 
     Args... nestArgs; // I DONT KNOW WHAT TO DO HERE 
     void setup(Func func, Args... args) { 
      nestFunc = func; 
      nestArgs = (args)...; // SO I CAN SET IT HERE 
     } 
     // Later I will forward this and run the function with its arguments 
     unsigned process() { 
      nestFunc(std::forward<Args>(nestArgs)...); // USE IT HERE 
      return 0; 
     } 
    }; 
    nest* myNest; 
    myNest->setup(func, (args)...); 
} 

これがために関係するすべてのものの一例です問題は、私は後での引数を格納する必要があります私の巣の構造体で呼び出す。また、あなたがそれを保存する解決策を持っているが、設定する方法が私のものと異なる場合は、それについても教えてください。ありがとう。

+2

'のstd ::タプル' - また、 'のstd :: bind'と'std :: function'とすべての楽しいものです。 – Xeo

答えて

17

::std::tuple<Args...>を使用して保存する必要があります。しかし、問題は、必要な時にそれを解凍する方法です。そのためには、「インデックス」というテクニックを使用する必要があります。

ここでは、私があなたがやろうとしていることをほぼ行った場所へのリンクです。ここで一番重要なクラスは、suspended_callです。

https://bitbucket.org/omnifarious/sparkles/src/tip/sparkles/deferred.hpp?at=default

少しだけで、私が最も関連性の高いビットを抽出し、コードの観点に入れましょう。

This line

auto saved_args = ::std::make_tuple(::std::move(args)...); 

はタプルに引数を保存します。私はそこに::std::moveを使用しました、そして、私はそれが正しいことだと思います。しかし、それは私が間違っている可能性があり、私は::std::forwardを使用する必要があります。私は、シグナリングの意図とは別の正確な違いについて明確にされていません。

実際に保存された引数で呼び出しを行うコードはhereです。コードは、私がやっていることを正確に特定しています。インデックスを実装するビットは、::std::get<I>テンプレートを引数として使用するインデックスにマップする整数のパックを作成することを含みます。この整数のパックを取得したら、それを使用して::std::getへの呼び出しを展開し、すべてのタプル要素を個別の引数として取得できます。

私は比較的簡単な方法であることないコードを思い付くしようとするでしょう:

#include <tuple> 
#include <cstddef> 
#include <string> 
#include <utility> 

template < ::std::size_t... Indices> 
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 FuncT, typename ArgTuple, ::std::size_t... Indices> 
auto call(const FuncT &f, ArgTuple &&args, const indices<Indices...> &) 
    -> decltype(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...)) 
{ 
    return ::std::move(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...)); 
} 

template <typename FuncT, typename ArgTuple> 
auto call(const FuncT &f, ArgTuple &&args) 
    -> decltype(call(f, args, 
         build_indices< ::std::tuple_size<ArgTuple>::value>{})) 
{ 
    const build_indices< ::std::tuple_size<ArgTuple>::value> indices; 

    return ::std::move(call(f, ::std::move(args), indices)); 
} 

int myfunc(::std::string name, const unsigned int foo) 
{ 
    return 0; 
} 

int foo(::std::tuple< ::std::string, const unsigned int> saved_args) 
{ 
    return call(myfunc, ::std::move(saved_args)); 
} 

このコードの多くはthis page on the indices trickから借りました。

また、それはあなたの状況に少しばかり適応しなければならない種類のサンプルです。基本的にはcall(nestFunc, saved_args)と呼んでください。

+0

このタプルをどのように(args)...で設定しますか? – Luka

+1

これらの「身分証明書」についてもっと詳しく説明できますか? – 0x499602D2

+0

@David:はい、もっと多くの例。あなたはそれらを持っているはずです。私は実際にこれを最近行ったコードを書く必要がありました。 – Omnifarious

4

私はそれはしばらくしている知っているが、私は同様のニーズを持っていたし、この解決策を考え出した、それが誰かの役に立てば幸い:

#include <functional> 

template<typename Func, typename... Args> 
struct nest { 
    std::function<void()> callBack; 

    void setup(Func func1, Args... args) { 
     callBack = [func1, args...]() 
     { 
      (func1)(args...); 
     }; 
    } 

    unsigned process() { 
     callBack(); 
     return 0; 
    } 
}; 

template<typename Func, typename... Args> 
void handleFunc(Func func, Args&&... args) { 
    nest<Func, Args...> myNest; 
    myNest.setup(func, args...); 
} 
+0

ひどく不自由なC++パック構文の巧妙な回避策 –

+0

タプルではなくラムダの中のすべてが非常に賢いです。 – Omnifarious

関連する問題