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));
}
The
std::functionconstructor accepts a pointer to a data member as it's Callable. This works because of thestd::invokeunder the hood.Here's what happens:
std::functionconstructor takes the pointer to the data member.f_num(foo), it usesstd::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.The use of member pointers in this way is in accordance with the C++ standard, and allows for some powerful patterns in code.