【问题标题】:Pass a member function like a std::function in C++ (like in C#)传递成员函数,如 C++ 中的 std::function(如 C# 中)
【发布时间】:2013-01-13 21:46:42
【问题描述】:

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

【问题讨论】:

  • 它不是因为test不应该返回smth而拒绝编译吗,因为它声明返回voidideone.com/3sfQGU
  • @Lol4t0:同意,我只是尝试编译它,但有一个空的 test... 有效
  • 是的,我搞砸了 - 我在 stackOverflow 编辑器中编写了测试。编辑。
  • 是的,您可以提供一个易于编译的示例来说明您在做什么。正如所指出的,由于test 中的return 和大写Delegate 的不同,它不会编译。
  • 对不起,这只是一个例子。如果我删除 return 语句,我发现它仍然有效。我记得尝试过同样的事情但它没有编译 - 我认为这是因为我试图传递一个成员函数,而不是一个全局函数

标签: c# c++ function delegates std-function


【解决方案1】:
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 的形式。努力吧。

【讨论】:

  • 我搞砸了在 stackOverflow 编辑器中编写测试。不过,我看到它编译时没有错误的结果。我之前尝试过,但没有用 - 我想我使用的是成员函数
  • @Vee:我也更新了我的答案。您的实现不支持成员函数指针。你需要努力。
【解决方案2】:

成员函数也需要一个对象的实例才能工作。如果使用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+= 行中指定它。您可以修改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;
    }
};

【讨论】:

  • 谢谢,这更清楚了。有没有办法让它与“ d += test; ”语法一起工作?
  • runv1() 委托 += 运算符覆盖的参数类型是什么?
【解决方案3】:

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

两种解决方案:

  • 使用类似std::function&lt;void(s&amp;)&gt;
  • 将你的成员函数绑定到一个对象 std::bind(&amp;s::test,&amp;s);(就像 K-ballo 说的,Csq 做的那样)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 1970-01-01
    • 2017-01-18
    • 2014-01-22
    • 2017-12-01
    • 2017-08-27
    相关资源
    最近更新 更多