2017-05-06 4 views
0

バリデーションテンプレート関数に参照のリストを渡して別の関数に渡そうとします。私が書いたコードは以下の通りです:バリデーションテンプレートへの参照を渡すと、std :: reference-wrapperが使用されます

template <typename T> 
void fun(cv::Point_<T> & pt) { pt.x++; pt.y++; } 

template <class ... args> 
void caller(args & ... list) { 

    typedef typename std::tuple_element<0, std::tuple<args...> >::type T; 

    std::array<std::reference_wrapper<T>, sizeof...(list)> values {list ...  }; 

    for(int i=0; i<values.size(); i++) 
     fun(values[i]); 

} 

、私はこのように機能の発信者を呼び出す:

cv::Point2f a, b, c; 

caller(a, b, c); 

コンパイラ私に次のエラーを与える:

No matching function for call to 'fun' 
Candidate template ignored: could not match 'Point_' against 'reference_wrapper' 

私は行方不明?

+2

あなたは何をしようとしていますか?参照ラッパーは不要です。あなたは実際に各引数に対して 'fun'を呼び出そうとしていますか? –

+0

多かれ少なかれ。しかし、私の質問のコードは、実際のものの単純化です。 – thewoz

答えて

2

std::reference_wrapper<T>T&への暗黙的な変換を持っていますが、同時に暗黙的な変換とテンプレート引数控除の両方を使用することはできません、とテンプレート引数控除は、funを呼び出すことが必要です。これの目標は、すべてのargsを反復処理するかもしれないので

fun(values[i].get()); 
1

を試してみてください、ここでより一般的なソリューションです。私たちは、for_packを実装しようとしている。

template<typename... Args, typename F> 
void for_pack(F function, Args&&... args) { 
    using expand = int[]; 
    (void)expand{(function(std::forward<Args>(args)), void(), 0)..., 0}; 
} 

これはArgs内のすべてのargsためfunctionを実行します。

は今、あなたの関数callerは実装にはるかに簡単です:

template <typename... args> 
void caller(args&... list) { 
    for_pack([&](cv::Point_<T>& arg){ 
     fun(arg); 
    }, list...); 
} 
+0

@Walter申し訳ありませんが、修正されました。 –

+0

あなたは 'void()、'すべての 'expand'のものは必要ありません、私の答えを見てください。 – Walter

+0

@Walterはい、 'void()'が必要です。 'function'が' operator(int) 'を多重定義するオブジェクトを返すと、コンパイルエラーが発生します。ちなみに、あなたのソリューションは 'tmp'が使われていないという警告を出さなければなりません。実際に動作します。 –

2

がさらに簡単。これは、パラメータパックの展開はブレースのinitリストに発生する可能性があるという事実を使用しています

template <typename...Args> 
void caller(Args&...args) 
{ 
    auto tmp = { (func(args),0)..., 0 }; 
} 

です。 func()はvoidを返すので、単に{ func(args)... }を使用することはできませんが、(func(args),0)を使用してintを使用することはできません。最後に、最後の0は、空のパラメーターパックの場合にコードがコンパイルされ、何もしないことを保証することです。

あなたはこれを一般化し、パックのすべての要素に指定された汎用的な関数を呼び出すテンプレートを書くことができます(C++ 14)

int main() 
{ 
    int a=1; 
    double b=2.4; 
    auto func = [](auto&x) { std::cout<<' '<<x++; }; 
    call_for_each(func,a,b); 
    std::cout<<'\n'; 
    call_for_each(func,a,b); 
    std::cout<<'\n'; 
} 
このように使用することができる

template <typename Func, typename...Args> 
void call_for_each(Func &&func, Args&&...args) 
{ 
    auto unused = { (func(std::forward<Args>(args)),0)...,0 }; 
} 

これは、C++ 14ラムダ(auto引数を取る)を使用します。パラメータパックは、テンプレートパラメータcall_for_eachの最後に来なければなりません。

+0

しかし、それは私にとってはアラム語のようなものです。しかし、何が無効ではないのですか?戻り値を合計する必要がありますか? – thewoz

+0

それは別の(良い)質問です。投稿する。 – Walter

+0

@Walter 'call_for_each'は変更可能なラムダを受け入れることができないようです。 'Func const&func'を' Func func'あるいは 'Func && func'で置き換えても構いませんか?ありがとう。 –

関連する問題