Универсальная ссылка в указателе на функцию-член
У меня возникли проблемы с пониманием, почему следующий код не может скомпилировать
#include <iostream>
#include <typeinfo>
#define PRINT_FUNC() {std::cout << __PRETTY_FUNCTION__ << std::endl;}
struct Obj {
Obj(){PRINT_FUNC();}
int run (float f, char *c) {
PRINT_FUNC();
return 0;
}
int fly () {
PRINT_FUNC();
return 0;
}
};
template <typename OBJ, typename R, typename ... Args>
void call_obj_func (OBJ &&o, R(OBJ::*fn)(Args...), Args ... args) {
PRINT_FUNC();
(o.*fn)(args...);
}
int main () {
Obj o;
call_obj_func(o, &Obj::fly);
}
Для функции call_obj_func я ожидал, что тип OBJ будет использоваться для ОБОИХ типов rvlaue и lvalue. Однако при вызове с типом lvalue компилятор жалуется на неоднозначность использования типов: Obj и Obj&
Это означает, что компилятор не уверен, использовать ли копию объекта или ссылку на объект.
Я уверен, что есть некоторая синтаксическая ошибка, поскольку я хотел бы, чтобы функция call_obj_func была скомпилирована с типами lvalue и rvalue.
Мое предположение - указатель на функцию-член, поскольку синтаксис (Obj&::*fn) и (Obj::*fn) могут иметь различную семантику. (Хотя я нигде не могу найти различия).
1 ответ
Вы можете написать
template <typename OBJ, typename Method, typename ... Args>
void call_obj_func (OBJ &&o, const Method& fn, Args&& ... args) {
PRINT_FUNC();
(std::forward<OBJ>(o).*fn)(std::forward<Args>(args)...);
}
Как и в настоящее время, у вас есть конфликт с выводом типа (Obj&
против Obj
и у вас могут быть похожие проблемы с args
)