Передайте функцию-член как std :: function в C ++ (как в C #)

У меня есть шаблон класса Delegate с перегруженным оператором + =, который делает использование делегатов похожим на C #.

// ... generalized version of the template omitted from code
template<typename... TArgs>
class Delegate<void, TArgs...>
{
private:
using Func = std::function<void(TArgs...)>;
std::vector<Func> funcs;

public:
template<typename T> Delegate& operator+=(T mFunc) { funcs.push_back(Func(mFunc)); return *this; }
void operator()(TArgs... mParams) { for (auto& f : funcs) f(mParams...); }
};

Вот что я пытаюсь сделать:

struct s
{
void test() { }
void run()
{
Delegate<void> d;
d += [] { /* do something */ ; };
d += test; // does not compile
}
};

Есть ли способ разрешить d += test; работать?

2

Решение

void test(int x, int y) { return x - y; }

Как это можно скомпилировать? Эта функция должна ничего не возвращать. Тип возвращаемого значения: void,

Кроме того, я предполагаю, что вы определили (или объявили) основной шаблон:

template<typename R, typename... TArgs>
class Delegate;

Также предполагая, что delegate это опечатка, так как шаблон класса Delegate,

Во всяком случае, с test ничего не возвращая, компилируется нормально:

http://stacked-crooked.com/view?id=c56b7a2e758f8fbc361228834c90822b


Что касается указателей на функции-члены, ваша текущая реализация не поддерживает это. Обратите внимание, что нестатическая указатель на функцию-член принимает форму R (C::*MemPtr)(Args...) cv, Просто работай над этим.

3

Другие решения

Функции-члены также нуждаются в экземпляре объекта для работы. Вы можете указать его в качестве первого параметра, если извлекаете функцию, используя std::mem_fn и вы также можете привязать текущий объект к функции с std::bind

Код проясняет:

struct s
{
void test() { }
void run()
{
Delegate<void> d;
d += [] { /* do something */ ; };
d += std::bind(std::mem_fn(&s::test), this); // does compile
}
};

Я действительно не вижу пути для d += test, Вам действительно нужно передать фактический объект. Эта лямбда-версия еще яснее показывает, что вам нужен текущий объект:

struct s
{
void test() { }
void run()
{
Delegate<void> d;
d += [this] { test(); };
}
};

Конечно, вам не нужно назначать это в строке оператора + =. Вы можете изменить Delegate принять this в конструкторе, как показано ниже (runv1), или добавьте функцию-член, которая дает прокси-объект, который может добавить тестовую функцию (runv2): (Хотя я не проверял это)

struct s
{
void test() { }
void runv1()
{
Delegatev2<s, void> d(this);
d += test;
}
void runv2()
{
Delegate<void> d;
auto memd = d.getMemberDelegate(this);
memd += test;
}
};
1

Как сказал Наваз при редактировании, вы используете функцию-член (не сатирическую), она не совместима с сигнатурой void () вашей функции std :: function.

Два решения:

  • Используйте что-то вроде std::function<void(s&)>
  • привязать функцию-член к объекту, std::bind(&s::test,&s); (как сказал K-балл, и Csq сделал)

Более того, вы должны использовать rref и std :: forward для достижения идеальной пересылки.

0
По вопросам рекламы [email protected]