patterncppMinor
Functional composition of member function predicates
Viewed 0 times
predicatesfunctionmemberfunctionalcomposition
Problem
In C++11, it is en vogue to use small lambda expressions to produce ad-hoc predicates. However, sometimes it's fun to create predicates in a functional, "point-free" way. That way, no function bodies need to be inspected, the code is mildly self-documenting, and it's a great icebreaker at parties.
Suppose I have a
This is verbose and redundant. The point-free approach uses
This works fine. But now the problem: Suppose I want to further compose this predicate, say by negating it. In the lambda this would be a trivial change. But for the functional notation, we would like to use the library function
However, the obvious
The simple call wrapper shall define two nested types named
This breaks the composability with
I have written this type mangling work-around which strips the unwanted pointer:
Now I can compose the predicates:
```
std::not1(mangle(std::me
Suppose I have a
std::vector v, and I want to remove all the empty inner vectors. The lambda-style remove_if call might look like this:std::remove_if(v.begin(),
v.end(),
[](std::vector const & w) -> bool { return w.empty(); });This is verbose and redundant. The point-free approach uses
std::mem_fn:std::remove_if(v.begin(),
v.end(),
std::mem_fn(&std::vector::empty));This works fine. But now the problem: Suppose I want to further compose this predicate, say by negating it. In the lambda this would be a trivial change. But for the functional notation, we would like to use the library function
std::not1 to produce a unary_negate wrapper.However, the obvious
std::not1(std::mem_fn(&std::vector::empty)) does not compile. The problem appears to be that the result type of std::mem_fn defines its argument_type member type as a pointer to the class, not a reference; cf. 20.8.10/2:The simple call wrapper shall define two nested types named
argument_type and result_type as synonyms for cv T* and Ret, respectively, when pm is a pointer to member function with cv-qualifier cv and taking no arguments, where Ret is pm’s return type.This breaks the composability with
std::not1.I have written this type mangling work-around which strips the unwanted pointer:
#include
template
struct result_type_mangler : T
{
using argument_type = typename std::remove_pointer::type;
result_type_mangler(T t) : T(t) { }
};
template
result_type_mangler mangle(T t)
{
return result_type_mangler(t);
}Now I can compose the predicates:
```
std::not1(mangle(std::me
Solution
The verbosity of C++14 generic lambdas should be much lower than
If you want to remove non-empty vectors, you can also do something like
Oh and the
I think Scott Meyers even has an Item "Prefer lambdas over bind" in his upcoming book Effective C++11/14.
std::mem_fun std::remove_if(v.begin(),
v.end(),
[](auto const & w) { return w.empty(); });If you want to remove non-empty vectors, you can also do something like
std::function)> is_empty = [](auto const & w) { return w.empty(); };
std::remove_if(v.begin(),
v.end(),
std::not1(is_empty));Oh and the
-> bool in your question is already superfluous in C++11 for single-line lambdas. Generic lambdas are currently supported by Clang >= 3.4, GCC 4.9 and MSVC 2013 November CTP.I think Scott Meyers even has an Item "Prefer lambdas over bind" in his upcoming book Effective C++11/14.
Code Snippets
std::remove_if(v.begin(),
v.end(),
[](auto const & w) { return w.empty(); });std::function<bool(std::vector<int>)> is_empty = [](auto const & w) { return w.empty(); };
std::remove_if(v.begin(),
v.end(),
std::not1(is_empty));Context
StackExchange Code Review Q#37917, answer score: 3
Revisions (0)
No revisions yet.