Functional Utilities for C++14.
Fu hopes to offer
- Utilities for defining functions in terms of other ones.
- A set of transparent function objects for common operations like
add,eq, etc.. - Utilities for creating transparent function objects.
github: https://github.com/splinterofchaos/fu biicode: http://www.biicode.com/splinterofchaos/fu
It can be difficult in C++ to use template functions with higher order functions, like those defined in <algorithm>. For example:
#include <iostream>
template<class X>
void print(const X& x) {
std::cout << x;
}
int main() {
auto v = {1,2,3,4};
std::for_each(std::begin(v), std::end(v), std::bind(print<int>, std::placeholders::_1));
}Not only must we explicitely specify the type of print's arguments to avoid ambiguity, but std::bind's syntax is overly verbose and inconvenient. Using fu, we can write...
#include <algorithm>
#include <iostream>
#include <fu/utility.h>
auto print = fu::lshift(std::ref(std::cout));
int main() {
auto v = {1,2,3,4,5};
std::for_each(std::begin(v), std::end(v), print);
}Here, fu::lshift is a function object representing operator<<, and by supplying just one argument, we create a partial function. By default, fu will copy arguments when constructing partial functions, but std::ref prevents that.
FU also provides several projection functions such as proj, split, and join for use with <algorithm>. For more information, see "Common <algorithm> patterns".
"Transparent function object" means a function object that represents an overload set or has a templated function call operator such that it can be sent to higher order functions, like std::for_each, without needing to specify the types of its arguments. fu supplies a set of function objects, mirroring those supplied in <utility>, like add, sub(tract), less, eq(ual), and more. Given one argument, they create a partial application. Given many, they apply the arguments from left to right. For exmple, fu::add(1,2,3,4) would be equivalent to writing ((1+2)+3)+4, and fu::add(1)(2) would be equivalent to fu::add(1,2). fu::less(1,2,3) is equivalent to 1 < 2 && 2 < 3.
TODO
A multary (or "multiple-arity") function is one that takes two or more arguments. fu::multary enables a function to return a partial application if given only one argument.
// GCD implementation from n4061
constexpr int gcd_impl(int a, int b) {
return b ? gcd_impl(b, std::abs(a) % std::abs(b)) : std::abs(a);
}
constexpr auto gcd = fu::multary(gcd_impl);
constexpr auto gcd5 = gcd(5);
constexpr int five = gcd5(10); // five == gcd(5, 10)One might note that gcd is an associative operation; gcd(x, y, z) == gcd(x, gcd(y, z)). fu::lassoc (implying "left associativity") allows it to work on an arbitrary number of arguments.
constexpr auto gcd = fu::lassoc(fu::multary(gcd_impl));
constexpr int five = gcd(5, 10, 15, 20);Having many layers of nesting parenthesies can make code both harder to write and read. fu::pipe allows one to chain operations, silimar to how the ranges proposal by Erin Neibler uses piping.
constexpr auto gcd = fu::pipe(gcd_impl, fu::lassoc, fu::multary);
// Think of as: "gcd = gcd_impl | lassoc | multary;"Note that most of fu's utilities are transparent function objects, so we can pass them directly to higher order functions without ambiguity.