Sponsored Link •
|
Summary
The C++ functional header provides a way to bind values to function arguments. Here is a way to bind functions to function arguments using a technique I'm calling meta-binders for lack of a better term.
Advertisement
|
Here is a problem: given two vectors of booleans:
std::vector<bool> v1; std::vector<bool> v2; v1.push_back(true); v1.push_back(true); v1.push_back(false); v1.push_back(false); v2.push_back(true); v2.push_back(false); v2.push_back(true); v2.push_back(false);You can easily create a third vector which is the result of and-ing the values in the first vector with the values in the second vector as follows:
std::vector<bool> v3; std::transform( v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3), std::logical_and<bool>() );If you want to do the same thing but instead apply a logical xor operation you would have to define a new binary predicate since the STL does not provide one:
bool logical_xor(bool x, bool y) { return (x || y) && !(x && y); } std::vector<bool> v3; std::transform( v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3), std::logical_xor() );Even though this is easy enough, it brings up the question, can we create a predicate from existing predicates without declaring a new function or function object. The standard library isn't much help but it is possible if we introduce the concept of a meta-binder. A meta-binder binds function to the arguments of another function. An xor function could then be define inline as follows:
std::vector<bool> v3; std::transform( v1.begin(), v1.end(), v2.begin(), std::back_insert(v3), meta_bind2( std::logical_and<bool>(), std::logical_or<bool>(), std::not2(std::logical_and<bool>()) ) );Here is the meta-binder code for binding two binary functions to the arguments of another binary function object:
template<class BinOp, class BinOpArg1, class BinOpArg2> class meta_binder2 : public std::binary_function < typename BinOp::first_argument_type, typename BinOp::second_argument_type, typename BinOp::result_type > { protected: BinOp op; BinOpArg1 arg1; BinOpArg2 arg2; public: meta_binder2(BinOp x, BinOpArg1 a1, BinOpArg2 a2) : op(x), arg1(a1), arg2(a2) { } typename BinOp::result_type operator() (const typename BinOp::first_argument_type& x, const typename BinOp::second_argument_type& y) { return op(arg1(x, y), arg2(x, y)); } }; template<class BinOp, class BinOpArg1, class BinOpArg2> meta_binder2<BinOp, BinOpArg1, BinOpArg2> meta_bind2(BinOp op, BinOpArg1 arg1, BinOpArg2 arg2) { return meta_binder2<BinOp, BinOpArg1, BinOpArg2>(op, arg1, arg2); }I would be curious if there is an existing name for this technique, probably those more familiar with higher-order functional programming will have some good nomenclature for me.
Have an opinion? Readers have already posted 8 comments about this weblog entry. Why not add yours?
If you'd like to be notified whenever Christopher Diggins adds a new entry to his weblog, subscribe to his RSS feed.
Christopher Diggins is a software developer and freelance writer. Christopher loves programming, but is eternally frustrated by the shortcomings of modern programming languages. As would any reasonable person in his shoes, he decided to quit his day job to write his own ( www.heron-language.com ). Christopher is the co-author of the C++ Cookbook from O'Reilly. Christopher can be reached through his home page at www.cdiggins.com. |
Sponsored Links
|