Подтвердить что ты не робот

Вызов функции-члена в shared_ptr через указатель функции-члена в шаблоне

Это функция шаблона, которая принимает указатель (или объект-указатель) и функцию-член:

template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
    return (ptr->*func)();
}

Если работает с обычным указателем:

struct C
{
    int getId() const { return 1; }
};

C* c = new C;
example(c, &C::getId);    // Works fine

Но это не работает с интеллектуальными указателями:

std::shared_ptr<C> c2(new C);
example(c2, &C::getId);

Сообщение об ошибке:

error: C2296: '->*' : illegal, left operand has type 'std::shared_ptr<C>'

Почему? и как сделать что-то, что работает с обоими?

4b9b3361

Ответ 1

std::shared_ptr не поддерживает доступ к указателю на элемент оператора (т.е. ->* и .*). Таким образом, мы не можем ссылаться на указатели функций-членов с помощью ->* на нем напрямую. Вы можете изменить вызывающий синтаксис для использования operator* и operator.*, который работает как для сырых указателей, так и для интеллектуальных указателей.

template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
    return ((*ptr).*func)();
}

LIVE

Ответ 2

std::shared_ptr не имеет operator->*. У вас есть два основных варианта:

Вы можете написать перегрузку, которая принимает std::shared_ptr (возможно, одну для std::unique_ptr):

template <typename T, typename MemberFunctor>
int example(std::shared_ptr<T> ptr, MemberFunctor func )
{
    return ((ptr.get())->*func)();
}

Однако я бы предложил просто сделать example ссылкой на T и называть func на нем. example не нужно ничего знать о том, как хранится указатель, поэтому он не должен требовать всех этих дополнительных перегрузок.

template <typename T, typename MemberFunctor>
int example(T&& t, MemberFunctor func )
{
    return (std::forward<T>(t).*func)();
}

Теперь, если у вас есть std::shared_ptr<T>, вы вызываете example как:

example(*my_shared_ptr, my_func); 

Ответ 3

std::shared_ptr не перегружает operator ->*. Вы можете добавить перегрузку:

template <typename Ptr, typename MemberFunctor>
int example(std::shared_ptr<Ptr> ptr, MemberFunctor func )
{
    return (ptr.get()->*func)();
}