2

我有一个模板类 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;工作?

4

3 回答 3

3
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. 努力吧。

于 2013-01-13T21:58:20.383 回答
1

成员函数也需要一个对象的实例来处理。如果您使用提取函数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。你真的需要传递实际的对象。这个 lambda 版本更清楚地表明您需要当前对象:

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

当然,您不需要在 operator+= 行中指定它。你可以修改下面Delegatethis构造函数(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;
    }
};
于 2013-01-13T22:21:07.130 回答
0

正如 Nawaz 在编辑中所说,您使用成员(非 satic)函数,它与您的 std::function 的 void () 签名不兼容。

两种解决方案:

  • 使用类似的东西std::function<void(s&)>
  • 将你的成员函数绑定到一个对象,std::bind(&s::test,&s);(就像 K-ballo 说的和 Csq 一样)

此外,您应该使用 rref 和 std::forward 来实现完美转发。

于 2013-01-13T22:25:55.787 回答