3
\$\begingroup\$

Is this code correct?

It appears to work in g++ 4.8.3 and clang (bcc64), however appearing to work is no guarantee of correctness :)

The aim is to be able to replace a call to a member function:

void Master::go()
{
     std::string s;
     func(s);    // func is a member function of Master
}

with a function template that wraps this call (and would indeed work with any class, not just Master):

void Master::go()
{
    std::string s;
    call_function( func, s );    // pseudocode
}

which ends up calling this->func(s).

The code which seems to work:

#include <iostream>
#include <string>
#include <functional>

struct Master
{
    void func(std::string &s) { std::cout << "Master::func(" << s << ")\n"; }
    void go();
    Master() {}

private:
    Master(Master const &);
};

int main()
{
    Master m;
    m.go();
}

template<typename FuncT>
void call_function( std::function<FuncT> fp, std::string s )
{
    fp(s);
}

template<typename FuncT, typename Host>
typename std::function<FuncT> my_binder(Host *h, FuncT Host::*p)
{
    using std::placeholders::_1;
    return std::bind(p, h, _1);
}

void Master::go()
{
    std::string s("hello");
    call_function( my_binder(this, &Master::func), s );
}

If the code is correct, then is my function my_binder a good idea, or am I overlooking a simpler option?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I see a few potential problems that you might want to address. First, I'll have to say that it's not entirely clear what problem you're trying to solve. That is, it's not clear why one wouldn't just call func(s) as in your very first example.

Handle const functions and objects

The my_binder call doesn't currently handle const functions. For example, we can easily declare Master::func const. However, the template fails in this case. Things only get worse if we also make go const and then declare the instance m of Master to be const. I'm not just sure how to fix that.

Pass const string reference

A more minor issue is that the second argument to call_function ought to pass the string by reference to avoid creation of a temporary and can be const.

Consider using a lambda instead

Here's an implementation that doesn't use templates and may address your need.

void Master::go() const
{
    const std::string s("hello");
    [&](){func(s);}();
}

That funny looking last line is both declaration and call of a lambda. It (rather pointlessly in this case) captures all in-scope variables by reference, takes no parameters and invokes func(s). It then actually calls that lambda with no parameters. It's a complex way of just saying func(s) but then, so was call_function(my_binder(this, func), s); so I am hoping that wherever it made sense to do the latter, it may be better instead to use a lambda.

To me, this is much simpler and easier to understand, especially since you're using C++11.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.