Function Adapters and Binders - C++11, 4 of n

来源:互联网 发布:linux dirname 编辑:程序博客网 时间:2024/05/22 09:46

A function adapter is a function object that enables the composition of function objects with each other, with certain values, or with special functions.
Function adaptors provided by C++11.

1) The bind() Adapter - binds parameters for callable objects

using std;
using std::placeholder

// Normal binding
auto plus10 = bind(plus<int>(), _1, 10);
// internally calls plus<> (i.e., operator +), with a placeholder _1
// as first parameter/operand and 10 as second parameter/operand
cout << "+10: " << plus10(7) << endl; 

auto plus10times2 = bind(multiplies<int>(), bind(plus<int>(), _1, 10), 2);
cout << "+10 *2: " << plus10times2(7) << endl;

auto pow3 = bind(multiplies<int>(), bind(multiplies<int>(), _1, _1), _1);
cout << "x*x*x: " << pow3(7) << endl;

auto inversDivide = bind(divides<double>(), _2, _1);
cout << "invdiv: " << inversDivide(49,7) << endl;

// Call global function
char myToupper (char c)
{
    std::locale loc;
    return std::use_facet<std::ctype<char> >(loc).toupper(c);
}

bind(equal_to<char>(),  bind(myToupper,_1), bind(myToupper,_2)));
// Create func object: myToupper(param1)==myToupper(param2)

// Note that bind() internally copies passed arguments. To let the function object use a reference
// to a passed argument, use ref() or cref()

void incr (int& i)
{
    ++i;
}
int i=0;
bind(incr,i)(); // increments a copy of i, no effect for i
bind(incr,ref(i))(); // increments i

// Calling Member Functions
class Person {
private:
    string name;
public:
    Person (const string& n) : name(n) {
    }
    void print () const {
        cout << name << endl;
    }
    void print2 (const string& prefix) const {
        cout << prefix << name << endl;
    }
};

vector<Person> coll = { Person("Tick"), Person("Trick"), Person("Track") };
for_each (coll.begin(), coll.end(), bind(&Person::print,_1));
for_each (coll.begin(), coll.end(), bind(&Person::print2,_1,"Person: "));

bind(&Person::print,_1)
// defines a function object that calls param1.print() for a passed Person.
// That is, because the first argument is a member function, the next argument
// defines the object for which this member function gets called

bind(&Person::print2,_1,"Person: ")
// defines a function object that calls param1.print2("Person: ") for any passed Person

// bind pointers
vector<Person*> cp;
...
for_each (cp.begin(), cp.end(), bind(&Person::print, _1));

vector<shared_ptr<Person>> sp;
...
for_each (sp.begin(), sp.end(), bind(&Person::print, _1));

2) The mem_fn() Adapter
simply calls an initialized member function for a passed argument while additional
arguments are passed as parameters to the member function:

for_each (coll.begin(), coll.end(), mem_fn(&Person::print));
mem_fn(&Person::print)(n); // calls n.print()
mem_fn(&Person::print2)(n,"Person: "); // calls n.print2("Person: ")

// Binding to Data Members
map<string,int> coll;
int sum = accumulate (coll.begin(), coll.end(),
                                          0,
                                          bind(plus<int>(), _1, bind(&map<string,int>::value_type::second, _2)));
auto f1 = bind(&map<string,int>::value_type::second, _2);
auto f2 = bind(plus<int>(), _1, f1);
f2(value, *iter) => plus<int>(value, f1(*iter))
f1(*iter) => f1(pair<const string, int> p) => p.second 
(second is the data member of pair class, in order to access this data member, we need bind a pair instance)

WHY SO COMPLICATED ?
We have more powerful weapon, lambdas
!!!

// accumulate implementation reference
template<class InputIt, class T, class BinaryOperation>
T accumulate(InputIt first, InputIt last, T value,  BinaryOperation op)
{
    for (; first != last; ++first) {
        value = op(value, *first);
    }
    return value;
}

3) not1() and not2 are almost deprecated since C++11, and so others.