2012-01-11 12 views
6

私は関数テンプレートapplyを書いて、何らかの関数f、整数i、およびパラメータパックを受け取っています。 applyは、i番目のパラメータpiを除いて、パラメータを解凍してfを適用する必要があります。 piについては、fのパラメータとして渡す前に、他の関数gを呼び出す必要があります。パラメータパックを分割する方法は?

パラメータパックを左側に、i番目のパラメータと右側に分割する方法が必要なようです。これは可能ですか?コード内:

template<int i, typename Function, typename... Parms> 
    void apply(Function f, Parms... parms) 
{ 
    auto lhs = // what goes here? 
    auto pi = // what goes here? 
    auto rhs = // what goes here? 

    f(lhs..., g(pi), rhs...); 
} 
+2

piはmath.hのM_PIとして入手できます。残りの部分についてはわかりませんが、より省略記号の少ないコードを投稿できますか? –

+2

@HansPassant私はOPが 'pi 'によって' ith-parameter'を意味すると思っています –

+5

@HansPassant C++は今や全面的に行きました。あなたはもうコードを一切書く必要はありません!省略記号は実際にコードで実行されています! –

答えて

3

OK、ここに行く!それは実際に醜いですが、私は急いでより良いバージョンを思いつくことができませんでした;)ほとんどのものは、沼の標準テンプレート特化です。最大の問題は、適切なサイズの整数のリストを作成することです。私は素敵なバージョンを思いついたが、何とか私がやったことを思い出すことができないことを思い出しているようだ。楽しい!

#include <iostream> 
#include <utility> 

// printing the values 
void print_args() {} 
template <typename F> void print_args(F f) { std::cout << f; } 
template <typename F, typename... T> 
void print_args(F f, T... args) 
{ 
    std::cout << f << ", "; 
    print_args(args...); 
} 

// the function object to be called: 
struct Functor 
{ 
    template <typename... T> 
    void operator()(T... args) 
    { 
     std::cout << "f("; 
     print_args(args...); 
     std::cout << ")\n"; 
    } 
}; 

// conditionally apply g(): 
template <typename T> T g(T value) { return 1000 + value; } 
template <int i, int j, typename T> 
typename std::enable_if<i != j, T>::type forward(T t) { return t; } 
template <int i, int j, typename T> 
typename std::enable_if<i == j, T>::type forward(T t) { return g(t); } 

// create a series of integers: 
template <int... Values> struct values {}; 

template <int Add, typename> struct combine_values; 
template <int Add, int... Values> 
struct combine_values<Add, values<Values...>> 
{ 
    typedef values<Values..., Add> type; 
}; 

template <int Size> struct make_values; 
template <> struct make_values<0> { typedef values<> type; }; 
template <int Size> 
struct make_values 
{ 
    typedef typename combine_values<Size, typename make_values<Size -1>::type>::type type; 
}; 

// applying f(t...) except for ti where g(ti) is called 
template <int i, int... Values, typename Function, typename... T> 
void apply_aux(values<Values...>, Function f, T... t) 
{ 
    f(forward<i, Values>(t)...); 
} 

template <int i, typename Function, typename... T> 
void apply(Function f, T... t) 
{ 
    apply_aux<i>(typename make_values<sizeof...(T)>::type(), f, t...); 
} 

int main() 
{ 
    apply<3>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8); 
    apply<4>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8); 
    apply<5>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8); 
} 
+0

これを使用して終了しました。ありがとう! –

3

実際には少し前と同じようにコード化されました。だから、次のコードを試してみてください。

template<unsigned N, unsigned M> 
struct call_up_impl{ 
    template<class Func, class Mutator, class Tuple, class... Args> 
    static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) { 
     call_up_impl<N-1, M>::do_call(func, mutator, args, std::get<N-1>(args), std::forward<Args>(unpacked_args)...); 
    } 
}; 

template<unsigned M> 
struct call_up_impl<0, M> { 
    template<class Func, class Mutator, class Tuple, class... Args> 
    static void do_call(const Func& func, const Mutator&, const Tuple&, Args&&... unpacked_args) { 
     func(std::forward<Args>(unpacked_args)...); 
    } 
}; 
template<unsigned M> 
struct call_up_impl<M, M> { 
    template<class Func, class Mutator, class Tuple, class... Args> 
    static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) { 
     call_up_impl<M-1, M>::do_call(func, mutator, args, mutator(std::get<M-1>(args)), std::forward<Args>(unpacked_args)...); 
    } 
}; 
template<int i, typename Function, typename... Parms> 
void apply(Function f, Parms... parms) { 
     std::tuple<Parms...> t(parms...); 
     call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t); 
} 

これは私の元のコードの迅速な適応ですので、これを行うにはいない最適な方法を徹底的にテストし、そうでないかもしれないされていないが、それは少なくとも、(少なくとも動作するはずですクイックテストによると正確に何が欲しいかによる)。タプルなしでこれを行うことは可能ですが、g ++でコンパイルすることはできません(入れ子になったバリデーショナルなテンプレートが必要なのではないようです)。おそらくタプルによって導入されたオーバーヘッドのほとんどを避けることができます

template<int i, typename Function, typename... Parms> 
void apply(Function f, Parms&&... parms) { 
     std::tuple<Parms&&...> t(std::forward<Parms>(parms)...); 
     call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t); 
} 

:しかしにapplyを変更します。 std::getコールの結果を正確に転送する方が良いかもしれませんが、私はあまりにも疲れています。

+0

これはもっと複雑に思えますし、すべての作業を行うために 'std :: tuple'にも依存しています!確かに、標準クラス( 'std :: enable_if')も使用していますが、' std :: enable_if'の実装は 'std :: tuple'と比較しています。私のコードのかなりの部分は実際に操作を適用し、結果を印刷しています。 –

+0

@DietmarKühl:私は、より複雑な部分を見ていることに同意します。とにかくvariadicテンプレートを使用しているためだけにC++ 11にバインドされている場合、 'std :: tuple'に頼っている問題は何ですか?(必要なタプル操作を実装するバリデーショナルなテンプレートに加えて、非常に簡単です)。それで問題は何ですか? – Grizzly

+0

どちらのソリューションも面白いです。それらを提供してくれてありがとう。それでも、C++ 11ではこれ以上の直接的な解決策はないことに失望しています。 –

関連する問題