Универсальная ссылка в указателе на функцию-член

У меня возникли проблемы с пониманием, почему следующий код не может скомпилировать

#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)...);
}

Live Demo

Как и в настоящее время, у вас есть конфликт с выводом типа (Obj& против Objи у вас могут быть похожие проблемы с args)

Другие вопросы по тегам