Ton van den Heuvel Ton van den Heuvel - 1 month ago 10
C++ Question

Why can std::ref be used to use member functions as callable types?

Please consider the following template function, that takes a callable, evaluates it, and returns the result (just for illustrative purposes):

template<typename F, typename... A>
auto evaluate(F&& f, A&&... args) -> decltype(f(std::forward<A>(args)...))
return f(args...);

This works for free-standing functions, but it breaks when passing member functions as follows for example, where
is an instance of

evaluate(&Foo::bar, foo, ...);

It complains about not being able to call the member function:

error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘f (...)’,
e.g. ‘(... ->* f) (...)’ auto evaluate(F&& f, A&&... args) -> decltype(f(std::forward<A>(args)...))

does allow passing member functions:

template<typename F, typename... A>
auto evaluate(F&& f, A&&... args) -> decltype(std::ref(f)(std::forward<A>(args)...))

Why does this work?


The functionality of making a reference_wrapper callable if the wrapped object is callable is fundamental to the ability to pass references to function objects into standard algorithms and the like.

here we create a tuple of references to function object:

int main()
    struct A {
        void operator()() const {
            std::cout << "A\n";

    struct B {
        void operator()() const {
            std::cout << "B\n";

    A a;
    B b;

    auto ab = std::tie(a, b);


And here we pass a reference to a stateful function object into a standard algorithm:

struct EqualAndCount
    EqualAndCount(char sought) : sought_(sought) {}

    template<class R>
    bool operator()(R const& r)
        return sought_ == r;
    std::size_t counter_ = 0;
    char sought_;

int main()
    EqualAndCount eq('j');
    auto s = std::string("abcdefghijklmnop");
    auto i = std::find_if(s.begin(), s.end(), std::ref(eq));

    std::cout << "searched " << eq.counter_ << " chars";
    if (i == s.end())
        std::cout << " and did not find it\n";
        std::cout << " and found it\n";

expected output:

searched 10 chars and found it

Why does this work?

Because std::reference_wrapper::operator() is written in terms of the mythical INVOKE (up to c++14) and in terms of std::invoke (c++17).

documentation here: