Why does std::function accept a data member pointer?

169 Views Asked by At

This code is extracted and simplified from std::function

#include <functional>
#include <iostream>
 
struct Foo
{
    int num_;
};

int main()
{
    const Foo foo(314159);
     // store a call to a data member accessor
    std::function<int(Foo const&)> f_num = &Foo::num_;
    std::cout << "num_: " << f_num(foo) << '\n';
}

Why does this std::function accept a pointer to the data member, and why does f_num(foo) totally work?

I've checked that it used this constuctor:

#if _USE_FUNCTION_INT_0_SFINAE
    template <class _Fx, typename _Mybase::template _Enable_if_callable_t<_Fx&, function> = 0>
#else // ^^^ _USE_FUNCTION_INT_0_SFINAE // !_USE_FUNCTION_INT_0_SFINAE vvv
    template <class _Fx, class = typename _Mybase::template _Enable_if_callable_t<_Fx&, function>>
#endif // _USE_FUNCTION_INT_0_SFINAE
    function(_Fx _Func) {
        this->_Reset(_STD move(_Func));
    }

https://godbolt.org/z/vTKfsWMhG

1

There are 1 best solutions below

3
NoName On BEST ANSWER

The std::function constructor accepts a pointer to a data member as it's Callable. This works because of the std::invoke under the hood.

Here's what happens:

  • The std::function constructor takes the pointer to the data member.
  • When you call f_num(foo), it uses std::invoke, which knows how to handle pointers to data members. In this context, it treats the pointer as a function that takes an object and returns the referenced data member.
  • This lets you perform operations like sorting by specific class members, providing a versatile way to work with class members.

The use of member pointers in this way is in accordance with the C++ standard, and allows for some powerful patterns in code.