2012-09-03 12 views
6

渡された関数が暗黙的にstd::functionにキャストされるように、反復可能関数と関数を受け入れるテンプレート関数を作成しようとしています。 (したがって、完全な関数とラムダの両方で使用することができます)。(g ++ 4.7.1)明示的な型名を同等のクラスtypedefに置き換えることはできません

は、ここでは、コードです:g++-4.7 -std=c++11 -o itest itest.cppでコンパイル

#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <typeinfo> 


template<typename T> 
void bar(const T & base, std::function<bool(int)> f) // works 
//void bar(const T & base, std::function<bool(typename T::iterator::value_type)> f) // fails to compile 
{ 
    std::cout << ((typeid(std::function<bool(int)>) == typeid(std::function<bool(typename T::iterator::value_type)>))?"identical":"distinct") << std::endl; 
} 

bool filter(int x) { return x%2==0; } 

int main() { bar(std::vector<int> {0, 1}, filter); } 

これはidenticalを生成します。

代わりにコンパイルが

g++-4.7 -std=c++11 -Wall -Werror -o itest itest.cpp 
itest.cpp: In function 'int main()': 
itest.cpp:16:53: error: no matching function for call to 'bar(std::vector<int>, bool (&)(int))' 
itest.cpp:16:53: note: candidate is: 
itest.cpp:9:10: note: template<class T> void bar(const T&, std::function<bool(typename T::iterator::value_type)>) 
itest.cpp:9:10: note: template argument deduction/substitution failed: 
itest.cpp:16:53: note: mismatched types 'std::function<bool(typename T::iterator::value_type)>' and 'bool (*)(int)' 

で失敗し、あなたのコメントを解除ライン10とコメント行9場合は、上記のようにコンパイルし、私は(適切なオプションを設定した)無修正版はXcodeのに成功したことに注意する必要がありますが、私は」可能であれば、g ++に固執することを好みます。何か間違っているのですか、これはg ++の既知のバグですか?

答えて

5

申し訳ありませんが、あなたのコードにはバグがあります。それはと同等です:

template<typename T> struct S { template<typename U> S(const U &); }; 
template<typename T> void bar(T, S<T>); 
int main() { bar(5, 6); } 

問題は、テンプレート引数が複数の引数に(直接または依存の型を構築する上で)表示されている場合、テンプレート引数控除/置換で、両方の引数が完全に一致していることです。 1つの引数からその型が何であるかが明白であっても、ユーザー定義の変換は考慮されません。

ここでのユーザー定義の変換は、暗黙のコンストラクタstd::function<...>です。

可能な修正がbar明示的に(bar<int>など)をインスタンス化する、またはヘルパー関数に派遣することになります。

template<typename T> 
void bar_impl(const T & base, std::function<bool(typename T::iterator::value_type)> f) 
{ 
    std::cout << ((typeid(std::function<bool(int)>) == typeid(std::function<bool(typename T::iterator::value_type)>))?"identical":"distinct") << std::endl; 
} 

template<typename T, typename F> 
void bar(const T & base, F &&f) 
{ 
    bar_impl<T>(base, std::forward<F>(f)); 
} 
+0

ありがとう、ありがとう。私は別の(むしろ恐ろしい)回避策を実装しました.1つは、呼び出し側が第2の型を参照または導出する必要がない方法です。 – Bakkot

+0

おっと、[リンク](https://gist.github.com/a172651b93dc4670f295)を忘れました。両方を読んで欲しくない人にとって、それは本質的にカレーです。 – Bakkot

2

あなたはポインタの機能のための2番目のオーバーロードを必要とする - それがコンパイルされます。 std::function文句を言わない仕事への暗黙のキャスト:

void bar(const T & base, bool(*f)(typename T::value_type)){ 
    std::cout << "ptr func\n"; 
} 

(関数signutre内の型と一致しないと、いくつかのT、)ecatmurによって記述問題の周りの仕事:あなたがそうのように定義されてidentity構造体に他のTをラップすることができます。

template<class T> struct identity{ typedef T type; }; 

コンパイラは、タイプ控除のためにこれらのTを無視します。

関連する問題