Какова моя конечная цель?
Я бы хотел, чтобы пользователь моей библиотеки мог указать карту произвольных имен полей и указателей на функции-члены, связанные с этими именами полей. Примером может быть следующее:
class Foo {
private:
int field_1_;
double field_2_;
public:
int field_1() const { return field_1_; }
double field_2() const { return field_2_; }
};
std::map<std::string, any_mem_fn> fields = {
{ "field_1", &Foo::field_1 },
{ "field_2", &Foo::field_2 }
};
Как видите, проблема в том, что подписи функций-членов могут быть разными.
Что я пробовал?
Я попытался создать класс any_mem_fn
, в котором хранится любой указатель на функцию-член. Класс выглядит следующим образом:
class any_mem_fn {
struct base_mem_fn_ptr {
virtual ~base_mem_fn_ptr() {}
virtual double operator()(Foo& foo) = 0;
};
template <typename F>
struct mem_fn_ptr : base_mem_fn_ptr {
F fn;
mem_fn_ptr(F&& f)
: fn(std::forward<F>(f))
{}
double operator()(Foo& foo) override {
return std::invoke(fn, foo);
}
};
public:
any_mem_fn() : fn_(nullptr) {}
any_mem_fn(any_mem_fn&& rhs) = default;
any_mem_fn(any_mem_fn const& rhs) = default;
template <typename F>
any_mem_fn(F&& f) {
fn_ = std::make_shared<mem_fn_ptr<F>>(std::forward<F>(f));
}
any_mem_fn& operator=(any_mem_fn&& rhs) = default;
any_mem_fn& operator=(any_mem_fn const& rhs) = default;
~any_mem_fn() = default;
template <typename T>
double value(T&& obj) {
return std::invoke(*fn_, obj);
}
private:
std::shared_ptr<base_mem_fn_ptr> fn_;
};
Здесь, как вы можете видеть, я использовал полиморфизм для стирания типа. Кроме того, вы можете заметить, что operator()
в случае каждой сигнатуры функции возвращает double
. Это преднамеренное , и в настоящее время это не моя проблема, поэтому, пожалуйста, не обращайтесь к этому.
Теперь, в чем проблема с вышеуказанным классом ... Проблема в том, что он работает только для функции-члены класса Foo
. Если я попытаюсь сохранить функцию-член класса Bar
, приведенный выше код не будет работать. Для того чтобы приведенный выше код работал в случае любого класса, мне нужно было бы перегрузить operator()
для каждого указанного класса c, что я не могу сделать, потому что моя библиотека не знает обо всех классах, которые есть у пользователя библиотеки.
Полная демонстрация: здесь .
Библиотека, над которой я работаю, здесь .
Вопрос: Можно ли каким-то образом сохранить какую-либо функцию-член класса в классе и иметь возможность вызывать эту функцию-член позже для объекта?