О shared_ptr и указателе на оператор-член `- & gt; *` и `std :: bind`

Недавно я обнаружил, что shared_ptr не имеет указателя на член оператора ->*, Я создал простой пример:

template <typename Pointer, typename Function, typename... Args>
auto invoke1(Pointer p, Function f, Args... args) -> decltype((p->*f)(args...))
{
return (p->*f)(args...);
}
struct A {
void g() { std::cout << "A::g()\n"; }
};
int main() {
A a;
invoke1(&a, &A::g); // works!!
std::shared_ptr<A> sa = std::make_shared<A>();
invoke1(sa, &A::g); // compile error!!
}

Q1: почему так? Почему shared_ptr не имеет этого оператора?

Я добавил такой оператор для shared_ptr и пример начал работать:

template <typename T, typename Result>
auto operator ->* (std::shared_ptr<T> pointer, Result (T::*function)()) ->decltype(std::bind(function, pointer))
{
return std::bind(function, pointer);
}
template <typename T, typename Result, typename Arg1>
auto operator ->* (std::shared_ptr<T> pointer, Result (T::*function)(Arg1 arg1)) ->decltype(std::bind(function, pointer, std::placeholders::_1))
{
return std::bind(function, pointer, std::placeholders::_1);
}

Q2: это правильная реализация для этого оператора? Есть ли где-нибудь какие-нибудь «золотые» правила, как реализовать такого оператора, возможно, я либо заново изобрел колесо, либо пошел в совершенно неверном направлении, как вы думаете? Есть ли способ иметь единственную функцию, реализующую этот оператор, вместо того, чтобы столько функций, сколько заполнителей в std …

После этого я пришел к выводу, что std::bind может быть использован в моем invoke метод.

template <typename Pointer, typename Function, typename... Args>
auto invoke2(Pointer p, Function f, Args... args)
-> decltype(std::bind(f, p, args...)())
{
return std::bind(f, p, args...)();
}

Таким образом, мой пример также работает без добавления operator ->* в shared_ptr,

Q3: Итак, это std::bind теперь рассматривается как замена operator->*?

10

Решение

В двух словах: да std :: bind является заменой указателей на функции-члены.

Зачем? потому что указатели на функции-члены ужасны, и их единственной целью является реализация делегатов, поэтому std :: bind и std :: function делают

Для справки о том, как реализованы указатели на функции-члены, смотрите мой предыдущий ответ Вот. Проще говоря, указатели на функции-члены ограничены стандартом, поскольку они не допускают вызовов после приведения; это делает их совершенно бессмысленными для такого поведения 90% людей хотят получить указатели на функции-члены: делегаты.

По этой причине std :: function используется для представления абстрактного «вызываемого» типа, а std :: bind используется для привязки этого к указателю на функцию-член. Вы абсолютно не должны связываться с указателями на функции-члены, а вместо этого использовать std :: bind и std :: function.

6

Другие решения

Я считаю, что самой простой мыслью было бы заменить «разыменование структуры» (->) оператор с парой разыграний (*) и структура ссылки (.) операторы:

template <typename Pointer, typename Function, typename... Args>
auto invoke1(Pointer p, Function f, Args... args) -> decltype(((*p).*f)(args...))
{
return ((*p).*f)(args...);
}
4

я верю shared_ptr не имеет оператора ->* потому что это невозможно реализовать для произвольного числа аргументов (что C ++ 11 позволяет делать для других случаев использования). Кроме того, вы можете легко добавить перегрузку invoke функция для умных указателей, которая вызывает get()Так что усложнять интерфейс не желательно.

2
По вопросам рекламы [email protected]