Better Function Objects in C++11

At the 2013 Meeting C++ conference, Eric Niebler argued in his keynote that we should be using function objects more often in C++. If I recall correctly, his argument was that function objects don’t participate in ADL.

Function objects have another advantage. They are easier to use in std::bind. If you pass a function pointer or a pointer to a member function to std::bind et al, you have to specify the exact function overload. Given

template<class T> 
struct foo {
    int bar(int a, int b) const { ... }
    int bar(int a, int b) { ... }
};

the following statement creates a unary function that takes an int x as argument and calls the const overloaded member function f.bar(0, x) on that instance:

foo<int> f;
auto fn_bar = std::bind(
    static_cast< int (foo<int>::*)(int, int) const >(
        &foo<int>::bar
    ), 
    f, 0, std::placeholders::_1
);

Eric advocated writing function objects like this instead:

struct bar_ {
    template<typename Foo>
    auto operator()(Foo&& foo, int a, int b) const 
        -> decltype(foo.bar(a, b)) 
    {
        return foo.bar(a, b);
    }
} bar;

The above bind can now be written as:

auto fn_bar = std::bind(bar, f, 0, std::placeholders::_1);

Much better. But wouldn’t it be better still if we could create a unary function object by writing

auto fn_bar = bar(f, 0, std::placeholders::_1); // 1

or even — let’s go crazy — by writing this:

auto fn_bar = bar(f, 0); // 2

Since bar is a ternary function that is only called with two arguments, it turns into a unary function fn_bar. Calling fn_bar(1) expands to bar(f, 0, 1). That is called currying and is supported e.g. in Scala and other functional programming languages.

All we need for this to work is a wrapper around our struct bar_ that can detect at compile time if

  1. bar is called with arguments that contain a std::placeholder
  2. bar is called with too few arguments

In these cases the object returned from a call to bar is actually a std::bind object, i.e. a function object. The first style of self-binding function objects has been implemented by Eric as part of his (experimental) range library. I’ve implemented the second style of function objects that automatically curry when the number of arguments is too low.

Eric’s imple
mentation supports chained function objects, it seems, i.e. calling f(g(std::placeholders::_1), 1, 2) should become a unary function. I didn’t get to that.

While I like the idea of leaving out the placeholders too, my own approach suffers from a serious drawback at the moment. My solution is, like Eric’s, based on std::bind and that needs to be passed the desired number of placeholders. Therefore my function object wrapper needs to know how many placeholders to pass to std::bind when it is called with n arguments. That means my function wrapper needs to know the arity of the wrapped function. There is no way to determine the arity of struct bar_ at compile time. bar_ could overload operator() of course with different numbers of arguments, so there isn’t a defined single function arity to begin with.

The solution: Remove my dependency on std::bind.

To be continued