2016-11-16 11 views
2

私のC++ 11の理解を広げるために、私は機能的なヘルパーを書いてみて、あまり冗長ではないと思うかどうかを見ています。次のコードを考えてみましょう:C++ 11では、バインドされたメソッドを含め、任意の呼び出し可能な引数を引数としてとる関数を呼び出すときにテンプレート引数を必要としない方法がありますか?

#include <list> 

int timesTwo(int x) { return x*2; } 
int timesX(int x, int y) { return x*y; } 

class Foo { 
public: 
    Foo(int a) : value(a) {}; 
    int fooTimesTwo() const { return value*2; }; 
    int value; 
}; 

template <class T, class U> 
std::list<U> myMap(const std::list<T> &list, const std::function<U(const T &)> &func) 
{ 
    std::list<U> result; 

    for(typename std::list<T>::const_iterator it = list.begin(); it != list.end(); ++it) { 
     result.push_back(func(*it)); 
    } 

    return result; 
} 

int main() 
{ 
    std::list<int> numbers = {1,2,3,4,5}; 
    std::list<int> numbers2 = myMap<int,int>(numbers, [] (int x) { return x*2; }); 
    std::list<int> numbers3 = myMap<int,int>(numbers, &timesTwo); 
    std::list<int> numbers4 = myMap<int,int>(numbers, std::bind(timesX, 2, std::placeholders::_1)); 

    std::list<Foo> fooList = {Foo(1), Foo(2), Foo(3), Foo(4)}; 
    std::list<int> numbers5 = myMap<Foo,int>(fooList, &Foo::fooTimesTwo);  
    return 0; 
} 

私のコード例では、それへの呼び出しのすべての4つのいずれかのテンプレート引数を必要としない

  1. ようmyMapを書き換えるとにかくがあり、...

  2. 一般的な実装は1つしかないので、呼び出すタイプの組み合わせごとにオーバーロードされたバージョンを手動で書き込む必要はありません。

私が代わりにstd::functionの第三テンプレートタイプであることをmyMapの第2引数を変更しようとしましたが、)は、第2のテンプレートタイプUを推測することができないので、それが失敗し、そしてb)でも、それであれば可能であれば、myMapへの4回目の呼び出しは、&Foo::fooTimesTwoが関数または関数ポインタではないため、行20にエラーが発生します。

私はC++ 11のさまざまな機能をすべて考慮していきたいと思っており、特に宣言や定義が曖昧になったり判読不能になったりすることはありません。私はそれが可能かどうか、もしそうなら、どのようなテクニックとC++ 11の機能がそれを達成できるのか疑問に思っています。

答えて

3

std::invokeをC++ 11に実装しようと試みることができますが、それは本当に面倒です。

それは一般呼び出し可能な機能テンプレートを作るためにかなり簡単です:

template <class T, class F> 
auto myMap(const std::list<T> &list, F&& func) 
    -> std::list<typename std::decay<decltype(func(*list.begin()))>::type> 
{ 
    using U = typename std::decay<decltype(func(*list.begin()))>::type; 
    std::list<U> result; 

    for(typename std::list<T>::const_iterator it = list.begin(); it != list.end(); ++it) { 
     result.push_back(func(*it)); 
    } 

    return result; 
} 

あなたは自由のための発現sfinaeを取得します。現在、メンバ関数ポインタだけが世話をしています:

template <class T, class F> 
auto myMap(const std::list<T> &list, F&& func) 
    -> std::list<typename std::decay<decltype(((*list.begin()).*func)())>::type> 
{ 
    return myMap(list, [=](T const& t){ return (t.*func)(); }); 
} 

これで、関数を期待どおりに呼び出すことができます。 demo


それでいる間、あなたがあったためで、この醜いforループ置き換えることができます:

for(auto const& elem : list) { 
    results.push_back(func(elem)); 
} 

またはアルゴリズムを使用します。このため

std::transform(list.begin(), list.end(), std::back_inserter(result), func); 
+1

感謝を!あなたの答えを勉強することで、私は自動車、宣言型、崩壊についてかなり学んできました。 – GuyGizmo

関連する問題