1

我一直在尝试使用 boost::bind 将对成员函数的调用发布到 io_strand 但一直出错。我已经设法为我正在尝试做的事情创建一个简单的等效示例,并且在以下上下文中看到了相同的错误:

我有以下包含我要调用的 doThings() 成员函数的类:

class base
{
public:
  int x = 1;

  template<typename B>
  void doThings(B&& b)
  {}
};

然后有一个子类(以准确表示我遇到错误的场景 - 我认为这没有区别)

class child : public base
{
  int y = 2;
};

我有以下代码试图进行 boost::bind 调用:

template<typename A>
void getInt(child c, A&& a)
{
  boost::bind((void(child::*)(A)) &child::doThings, &c, std::forward<A>(a))();
}

然后调用如下:

int main()
{
  child c = child();
  getInt(c, 7);
}

当我编译上面的代码时,我得到以下错误:

错误:没有匹配将函数“doThings”转换为类型“void (class child::*)(int)”</p>


如果我将 doThings() 的函数签名更改为采用常规 B 类型而不是通用引用,即 BB&&它编译运行没有问题。
我怀疑我的问题与我在 getInt() 中所做的演员表有关:

(void(child::*)(A))

但我不知道我需要将其更改为什么。A&&在这种情况下不起作用,因为我相信它会在那种情况下代表 r 值引用。我尝试时遇到的编译错误似乎证实了这一点:

错误:无法将“int”左值绑定到“int&&”</p>

为了完整性:如果我不尝试执行强制转换,那么我会收到以下编译错误:

错误:没有匹配的函数调用'bind(未解决的重载函数类型,child*,int)'</p>

有人可以告诉我我需要做什么才能使我的 boost::bind 调用在这种情况下有效吗?

我正在使用 C++11

4

1 回答 1

2

我建议不要使用boost::bind,因为lambda 表达式可用于干净地绑定参数(避免STLbind在本演讲中解释的许多陷阱)


我假设你想要:

  • a如果将右值引用传递给 ,则通过移动捕获getInt

  • a如果将左值引用传递给 ,则通过引用捕获getInt

我还假设:

  • A不在int您的真实代码中,否则完美转发将没有意义。

  • 您希望避免不必要的副本aA可能是仅移动类型。

  • 您只能访问 C++11 (而不是更新的标准)

如果您需要“完美捕获” a (即,如果A是右值引用,则按移动捕获,如果A是左值引用,则按引用捕获),您需要某种包装器。

不幸的是,这并不简单,尽管它在 C++14 和 C++17 中变得更好。这是最终语法的示例:

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`.
}

如您所见,您需要一个名为处理“完美捕获”的模板函数。forward_capture_wrapper您可以在以下资源中找到有关如何实现该功能的信息:

通过结合上面的资源,您应该能够在 C++11 中实现“完美的捕获包装器”。

您还需要一个forward_like辅助函数来保留a参数的原始值类别。你可以找到一个实现:

于 2017-01-25T16:27:24.520 回答