简体   繁体   English

在C ++中传递像std :: function这样的成员函数(例如在C#中)

[英]Pass a member function like a std::function in C++ (like in C#)

I have a template class Delegate, with an overloaded += operator, that makes using delegates similar to 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...); }
    };

This is what I'm trying to do: 这就是我想要做的:

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

Is there a way to allow d += test; 有没有办法允许d += test; to work? 上班?

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

How can it compile? 如何编译? This function is supposed to return nothing. 该函数应该不返回任何内容。 Its return type is void . 其返回类型为void

Also, I assume you have defined (or declared ) the primary template: 另外,我假设您已经定义(或声明了)主要模板:

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

Also assuming that delegate is a typo, as the class template is Delegate . 还假设delegate是一个错字,因为类模板是Delegate

Anyway, with test returning nothing, it compiles fine: 无论如何,在test什么也不返回的情况下,它可以正常编译:

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


As for member-function-pointers, your current implementation doesn't support it. 至于成员函数指针,您当前的实现不支持它。 Note that a non-static member function pointer takes the form of R (C::*MemPtr)(Args...) cv . 请注意, 非静态成员函数指针采用R (C::*MemPtr)(Args...) cv Just work on it. 只是努力。

Member functions need an instance of an object to work on as well. 成员函数也需要对象的实例才能进行处理。 You can give it as first parameter if you extract the function using std::mem_fn and you can also bind the current object to the function with std::bind 你可以把它作为第一个参数,如果你使用提取功能std::mem_fn ,你也可以将当前对象绑定到与功能std::bind

The code makes it clear: 该代码很清楚:

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

I don't really see a way for d += test . 我真的没有找到d += test You really need to pass the actual object. 您确实需要传递实际对象。 This lambda version shows it even more clearly that you need the current object: 这个lambda版本更加清楚地表明您需要当前对象:

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

Of course, you don't need to assign this in the operator+= line. 当然,您不需要在operator + =行中分配它。 You can modify the Delegate to take this in constructor like below ( runv1 ), or add a member function that gives a proxy object that can add the test function ( runv2 ): (I did not test these though) 您可以修改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;
    }
};

As Nawaz said in edit, you use a member (non satic) function, it isn't compatible with void () signature of your std::function. 正如Nawaz在编辑中所说,您使用的是成员函数(非satic),它与std :: function的void()签名不兼容。

Two solution : 两种解决方法:

  • Use something like std::function<void(s&)> 使用类似std::function<void(s&)>
  • bind your member function to an object, std::bind(&s::test,&s); 将您的成员函数绑定到对象std::bind(&s::test,&s); (like K-ballo said, and Csq did) (就像K-ballo所说的那样,Csq做到了)

Moreover, you should use rref and std::forward to achieve perfect forwarding. 此外,您应该使用rref和std :: forward来实现完美的转发。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM