How to best pass methods into methods of the same class

前端 未结 3 1484
你的背包
你的背包 2021-01-02 16:40

I have this C++ class that one big complicated method compute that I would like to feed with a \"compute kernel\", a method of the same class. I figure I would

3条回答
  •  离开以前
    2021-01-02 17:32

    As you suspected, passing a member function pointer is acceptable practice.

    If you need to know the syntax, it is:

    int compute_(int a, int b, int (test::*f)(int,int))
    {
       int c=0;
       // Some complex loops {
       c += (this->*f)(a,b)
       // }
       return c;
    }
    

    Representing member functions using integers, and switching, introduces programmer overhead to keep things up to date when the list of available operations changes. So you don't want that unless there's some important reason in a particular case.

    One alternative is to make compute even more general -- instead of taking a member function, write a function template that takes any callable type:

    template 
    int compute_(int a, int b, BinaryFunction f) {
        // body as before but `f(a,b)` instead of `(this->*f)(a,b)`
    }
    

    This more general template is great if someone wants to use it with some operator of their own invention, that isn't a member function of test. It's more difficult to use in the case of the member function, though, because someone needs to capture this. There are a few ways to do that -- a C++11 lambda, boost::bind, or writing out a functor longhand. For example:

    template 
    int compute_(int a, int b, BinaryFunction f) {
        // body as before with `f(a,b)`
    }
    
    int compute_(int a, int b, int (test::*f)(int,int))
    {
        return compute_(a, b, bind_this(f, this));
    }
    

    Defining bind_this is a bit of a pain: it's like std::bind1st except that we'd like to work with a 3-arg functor whereas bind1st only takes a binary functor. boost::bind, and std::bind in C++11, are more flexible, and will handle the extra arguments. The following will do for this case, but doesn't work in general to bind 2-arg member functions:

    struct bind_this {
        int (test::*f)(int,int);
        test *t;
        int operator(int a, int b) const {
            return (t->*f)(a,b);
        }
        bind_this(int (test::*f)(int,int), test *t) : f(f), t(t) {}
    };
    

    In C++11 you can just use a lambda:

    int compute_(int a, int b, int (test::*f)(int,int))
    {
        return compute_(a, b, [=](int c, int d){ return (this->*f)(c,d) });
    }
    

提交回复
热议问题