c++std-functionthis-pointer

Member functions called on non-pointer objects with std::function


Code is as the following.

std::string::empty() should take the this pointer as the parameter whose type is pointer, std::string *.

How could the calling at line 2 and 3 be OK?

#include <iostream>
#include <functional>

int main() {
    std::string str{"A small pond"};

    std::function<bool(std::string*)> fp = &std::string::empty;
    std::cout << fp(&str) << std::endl; // 1

    std::function<bool(std::string)> f = &std::string::empty;
    std::cout << f(str) << std::endl; // 2

    std::function<bool(std::string&)> fr = &std::string::empty;
    std::cout << fr(str) << std::endl; // 3
}

/*
output:
0
0
0
*/
clang version 9.0.0-2~ubuntu18.04.2 (tags/RELEASE_900/final)
g++ (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0

Solution

  • std::function can accept any Callable that matches its type signature. When invoked, the callable and arguments are evaluated with the following rules (quote cppreference):

    • If f is a pointer to member function of class T:
      • If std::is_base_of<T, std::decay_t<decltype(t1)>>::value is true, then INVOKE(f, t1, t2, ..., tN) is equivalent to (t1.*f)(t2, ..., tN)
      • If std::decay_t<decltype(t1)> is a specialization of std::reference_wrapper, then INVOKE(f, t1, t2, ..., tN) is equivalent to (t1.get().*f)(t2, ..., tN)
      • If t1 does not satisfy the previous items, then INVOKE(f, t1, t2, ..., tN) is equivalent to ((*t1).*f)(t2, ..., tN).

    So the first case is evaluated like (*t1).*f() and the other two are evaluated like t1.*f().