Этот код извлечен и упрощен из 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';
}
Почему этот std::function принимает указатель на элемент данных и почему f_num(foo) полностью работает?
Я проверил, что он использовал этот конструктор:
#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));
}
Указатель данных члена, прикрепленный к соответствующему объекту, приводит к ссылке. Поведение аналогично унарной функции доступа, вызываемой для объекта. Поэтому std решил рассматривать его как унарную функцию; за исключением того, что вы не можете обычно вызывать его с помощью оператора вызова функции (operator()). Это казалось удобным, когда они это решили. В настоящее время рекомендуется оборачивать привязки членов как лямбда-выражения для эффективности использования памяти ([object]{return object.data;} или [smart_ptr]{return smart_ptr->method();}).





Конструктор std::function принимает указатель на элемент данных, так как он Callable. Это работает из-за std::invoke под капотом.
Вот что происходит:
std::function принимает указатель на элемент данных.f_num(foo), он использует std::invoke, который знает, как обрабатывать указатели на элементы данных. В этом контексте он рассматривает указатель как функцию, которая принимает объект и возвращает указанный элемент данных.Использование указателей членов таким образом соответствует стандарту C++ и позволяет использовать в коде некоторые мощные шаблоны.
Хотя это и не ложь, этот текст звучит так, как будто комментарии были скопированы в ИИ, который вставил какой-то пушистый маркетинговый ход.
Может поэтому первый комментарий удалили
Он специально разработан для этого (он использует
std::invokeпод капотом), и результирующая функция вернет этот член. Позволяет вам делать всевозможные умные вещи, напримерstd::ranges::sortдля определенного члена класса (путем передачи ему указателя-члена в качестве проекции) (он не используетstd::function, но используетstd::invoke).