У меня есть шаблон класса 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;
работать?
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
, Просто работай над этим.
Функции-члены также нуждаются в экземпляре объекта для работы. Вы можете указать его в качестве первого параметра, если извлекаете функцию, используя 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;
}
};
Как сказал Наваз при редактировании, вы используете функцию-член (не сатирическую), она не совместима с сигнатурой void () вашей функции std :: function.
Два решения:
std::function<void(s&)>
std::bind(&s::test,&s);
(как сказал K-балл, и Csq сделал)Более того, вы должны использовать rref и std :: forward для достижения идеальной пересылки.