[英]How to boost::bind a template member function which takes a universal reference as a parameter
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. 我一直在尝试使用boost :: bind将对成员函数的调用发布到io_strand上,但是一直出错。 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: 我有以下包含要调用的doThings()成员函数的类:
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: 我有以下代码尝试进行boost :: bind调用:
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)'
错误:没有匹配项将函数'doThings'转换为'void(class child :: *)(int)'
If I change the function signature of doThings() to take a regular B type rather than a universal reference ie B
rather than B&&
then it compiles a runs with no issues. 如果我将doThings()的函数签名更改为采用常规B类型而不是通用引用(即
B
而不是B&&
则它将编译运行而没有问题。
I suspect my issue is something to with the cast I'm doing in getInt(): 我怀疑我的问题与我在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. A&&
在这种情况下不起作用,因为我认为它将代表该上下文中的r值引用。 The compilation error I get when I try it seems to confirm this: 我尝试时遇到的编译错误似乎证实了这一点:
error: cannot bind 'int' lvalue to 'int&&'
错误:无法将“ int”左值绑定到“ 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)'
错误:没有匹配的函数调用“ bind(未解析的重载函数类型,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? 有人可以给我启发,使我的boost :: bind呼叫在这种情况下有效吗?
I am using C++11 我正在使用C ++ 11
I would suggest against using boost::bind
, as lambda expressions can be used to cleanly bind arguments (avoiding many pitfalls of bind
explained in this talk by STL ) . 我建议不要使用
boost::bind
,因为lambda表达式可用于干净地绑定参数(避免STL在本次演讲中解释的bind
陷阱) 。
I'm assuming that you want to: 我假设您要:
Capture a
by move if an rvalue-reference is passed to getInt
. 捕捉
a
如果右值引用传递到由移动 getInt
。
Capture a
by reference if an lvalue-reference is passed to getInt
. 如果将左值引用传递给
getInt
则捕获a
按引用 。
I'm also assuming that: 我还假设:
A
is not int
in your real code, otherwise perfect-forwarding would not make sense. A
在您的实际代码中不是int
,否则完美转发将毫无意义。
You want to avoid unnecessary copies of a
or that A
could be a move-only type. 您要避免不必要
a
或A
可能是仅移动类型的副本。
You only have access to C++11 (and not to newer standards) . 您只能访问C ++ 11 (而不能访问较新的标准) 。
If you need to "perfectly-capture" a
(ie capture-by-move if A
is an rvalue-reference, capture-by-reference if A
is an lvalue-reference) , you need some sort of wrapper. 如果需要“完全捕获”
a
(即,如果A
是右值引用,则按移动捕获;如果A
是左值引用,则按引用捕获) ,则需要某种包装。
Unfortunately this is non-trivial , even though it gets better in C++14 and C++17. 不幸的是 ,即使在C ++ 14和C ++ 17中变得更好, 这也不是小事 。 Here's an example of how the final syntax could look:
下面是最终的语法如何能看一个例子:
template<typename A>
void getInt(child c, A&& a)
{
// `a_wrapper` stores an `A&` or an `A` depending on the value category
// of `a`. Copying it should not copy `a` - it should conditionally move
// it depending on the original value category of `a`.
auto a_wrapper = forward_capture_wrapper(std::forward<A>(a));
// `forward_like` retains information about `a`'s value category so that
// it can be used in the body of the lambda to forward the reference/value
// stored inside `a_wrapper`.
// vvvvvvvvvvvvvvv
[&a, a_wrapper]{ c.doThings(forward_like<A>(a_wrapper.get()); }();
// ^^^^^^^^^^^^^^^
// `a_wrapper.get()` returns a reference that can then be moved or passed
// to `c.doThings`.
}
As you can see, you need a template function called forward_capture_wrapper
that deals with "perfect-capture". 如您所见,您需要一个名为
forward_capture_wrapper
的模板函数来处理“ 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. “在lambda中移动捕获” -涵盖如何在C ++ 11中实现逐行捕获。 This is trivial in C++14 thanks to generalized lambda captures.
多亏了广义的lambda捕获,在C ++ 14中这是微不足道的。
"capturing perfectly-forwarded objects in lambdas" - this is an article I've written that covers how to implement "perfect capture" in C++14/17. “用lambda捕获完美转发的对象” -这是我写的一篇文章,内容涉及如何在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.
这是理解“完美捕获”问题的一个很好的起点,并且应该可以将代码转换为符合C ++ 11的代码。
"Capturing perfectly-forwarded variable in lambda" - this StackOverflow question I asked some time ago covers some ways of implementing "perfect capture" in C++14. “在lambda中捕获完美转发的变量” -我之前问过的这个StackOverflow问题涵盖了在C ++ 14中实现“完美捕获”的一些方法。
By combining the resources above you should be able to implement a "perfect capture wrapper" in C++11. 通过结合上面的资源,您应该能够在C ++ 11中实现“完美的捕获包装器”。
You also need a forward_like
helper function that preserves the original value category of the a
argument. 您还需要一个
forward_like
可以保留的原始值类的辅助功能a
说法。 You can find an implementation of that: 您可以找到一个实现:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.