Если obj
является T**
, то выполнение obj.*foo
является некорректным. Так что вам нужно только выяснить, является ли это указателем или не указателем. Вы можете использовать перегрузку для этого.
template<typename T, typename M> void f(T *obj, M m) { // pointer
(obj->*m)();
}
template<typename T, typename M> void f(T &obj, M m) { // not a pointer
(obj.*m)();
}
Это имеет недостаток, заключающийся в том, что он работает только с указателями на функции-члены с нулевым параметром и не возвращает значение (если оно есть), которое возвращают эти функции. Вы не можете сделать следующее (что может быть легко реализовано), потому что обе ветви будут проверены на тип
if(is_pointer(obj)) v = (obj->*m)(arg...); else v = (obj.*m)(args...);
Что вы можете сделать - просто вызвать функцию для разыменования вашего объекта, если он является указателем
template<typename T> T &deref(T *t) { return *t; }
template<typename T> T &deref(T &t) { return t; }
Тогда вы можете сказать
v = (deref(obj).*m)(args...);