(Note: As should already be clear from the tags, this is strictly C++03. Yes, I know, lambda makes all this pain go away (and brings in new kinds, I bet), but this is an embedded system, with an OS version from the 90s, and I am told I should be glad I have a C++03 compiler (GCC4.1.x, BTW), or a C++ compiler at all. So please abstain from posting C++11 solutions. No need to rub it in, really.
Also, std::bind()
, std::function()
etc. are, of course, actually in std::tr1
, but I edited out the tr1
prefix, because I thought it adds mostly only noise to the code.)
I have some server-like thing that I need to register functions with and I need to adapt them to call some object's similar, but slightly different, functions. These functions have different argument lists. The server "knows" that and when I try to register a function it only accepts one with the correct signature (as correct as std::function
requires, that is), depending on some magic tag passed in as a template argument.
Here's a sketch of the code:
// this I just use
class server {
public:
template<unsigned int MagicTag>
bool register_call(typename some_traits_type<MagicTag>::func_type);
};
// this needs to be called from the server
class X {
public:
bool foo();
bool bar(std::string&);
bool baz(int);
};
// this is the glue
class Y {
public:
Y(X& x) : x_(x) {
register_call<MAGIC_FOO>(&Y::foo );
register_call<MAGIC_BAZ>(&Y::bar, _1);
register_call<MAGIC_FBZ>(&Y::baz, _1);
}
private:
X& x_;
template<unsigned int MagicTag, typename Function>
bool register_call(Function function) {
somewhere->register_call<MagicTag>(std::bind( function
, this ));
}
template<unsigned int MagicTag, typename Function, typename PlaceHolder1>
bool register_call(Function function, PlaceHolder1 place_holder1) {
somewhere->register_call<MagicTag>(std::bind( function
, this
, place_holder1 ));
}
int foo() {return x_.foo() ? MAGIC_OK : MAGIC_FAILED;}
int bar(std::string& s) {return x_.bar(s) ? MAGIC_OK : MAGIC_FAILED;}
int baz(int i) {return x_.baz(i) ? MAGIC_OK : MAGIC_FAILED;}
};
This actually works, but in reality there are way more functions and doing this as a tedious copy'n'paste effort insults my sense of dignity and produces smelly code. Since all these functions do exactly the same, with the only difference being the function they call and the arguments they have, or do not have, to pass, I should be able to fold them into one parametrized function, hiding the differences behind std::bind()
. Failing this, I settled on first doing this for all the functions without any parameters (as in foo()
), which is the overwhelming majority.
So I wanted to route all the calls of foo()
-like function in X
through a single function Y::call_it
that does the tedious part:
int call_it(std::function<bool()> f) {return f() ? MAGIC_OK : MAGIC_FAILED;}
and bind the appropriate function in X
as an argument to it:
register_call<MAGIC_FOO>(&X::foo); // note the X!
// (this is wrong)
somewhere->register_call<MagicCode>( std::bind( std::bind( &Y::call_it
, this
, function )
, std::ref(x_) );
Obviously, this is wrong, and so are all my other attempts at solving this. (I have only been playing with std::bind()
for 10 weeks now, so please bear with me). In the end I got lost in an incredible maze of hilarious error messages out of std::function
's templatized guts that can bring a grown man down in tears and should feed a shrink and his extended family for a year at least.
So before I kill myself out of sheer frustration and orphan my kids — how can I do this?