I've been trying to use boost::bind to post a call to a member function onto an io_strand but have been getting errors. I have manged to create a simplistic equivalent example of what I am trying to do and have seen the same error in the following context:
I have the following class containing the doThings() member function I want to call:
class base
{
public:
int x = 1;
template<typename B>
void doThings(B&& b)
{}
};
There is then a subclass of this (to accurately represent the scenario I am encountering my error - I don't think it makes a difference)
class child : public base
{
int y = 2;
};
I have the following code trying to make the boost::bind call:
template<typename A>
void getInt(child c, A&& a)
{
boost::bind((void(child::*)(A)) &child::doThings, &c, std::forward<A>(a))();
}
And then this is being called as follows:
int main()
{
child c = child();
getInt(c, 7);
}
When I compile the above code I get the following error:
error: no matches converting function ‘doThings’ to type ‘void (class child::*)(int)’
If I change the function signature of doThings() to take a regular B type rather than a universal reference i.e.
B rather than B&& then it compiles a runs with no issues.
I suspect my issue is something to with the cast I'm doing in getInt():
(void(child::*)(A))
But I don't know what I would need to change it to. A&& wouldn't work in this context as I believe it would represent an r-value reference in that context. The compilation error I get when I try it seems to confirm this:
error: cannot bind ‘int’ lvalue to ‘int&&’
For completeness: if I don't attempt to perform a cast then I get the following compilation error:
error: no matching function for call to ‘bind(unresolved overloaded function type, child*, int)’
Could someone please enlighten me on what I would need to do in order to make my boost::bind call valid in this scenario please?
I am using C++11
I would suggest against using
boost::bind, as lambda expressions can be used to cleanly bind arguments (avoiding many pitfalls ofbindexplained in this talk by STL).I'm assuming that you want to:
Capture
aby move if an rvalue-reference is passed togetInt.Capture
aby reference if an lvalue-reference is passed togetInt.I'm also assuming that:
Ais notintin your real code, otherwise perfect-forwarding would not make sense.You want to avoid unnecessary copies of
aor thatAcould be a move-only type.You only have access to C++11 (and not to newer standards).
If you need to "perfectly-capture"
a(i.e. capture-by-move ifAis an rvalue-reference, capture-by-reference ifAis an lvalue-reference), you need some sort of wrapper.Unfortunately this is non-trivial, even though it gets better in C++14 and C++17. Here's an example of how the final syntax could look:
As you can see, you need a template function called
forward_capture_wrapperthat deals with "perfect-capture". You can find information on how to implement that in these resources:"Move capture in lambda" - covers how to implement capture-by-move in C++11. This is trivial in C++14 thanks to generalized lambda captures.
"capturing perfectly-forwarded objects in lambdas" - this is an article I've written that covers how to implement "perfect capture" in C++14/17. It's a good starting point to understand the issue of "perfect capture" and it should be possible to convert the code to something C++11 compliant.
"Capturing perfectly-forwarded variable in lambda" - this StackOverflow question I asked some time ago covers some ways of implementing "perfect capture" in C++14.
By combining the resources above you should be able to implement a "perfect capture wrapper" in C++11.
You also need a
forward_likehelper function that preserves the original value category of theaargument. You can find an implementation of that:In my
vrm_corelibrary.In this StackOverflow answer by T.C..