假设我们有以下层次结构:
class Add3Interface {
virtual int add3 (const int&) const = 0;
};
class Add3: public Add3Interface {
virtual int add3 (const int& arg) const override {
return arg + 3;
}
};
我想绑定
add3
方法,这样我就可以在 std::views::transform
之类的事情中使用它。
下面的代码就可以了:
const Add3 myAdder{};
const auto myFun = std::bind(&Add3::add3, myAdder, std::placeholder::_1);
但是,在我的用例中,我无权访问具体类型,因此我必须编写如下内容:
const Add3Interface& myAdder = Add3{};
const auto myFun = std::bind(&Add3Interface::add3, myAdder, std::placeholder::_1);
然而,这让编译器感到不安:
/usr/include/c++/11/tuple:238:13: error: cannot declare field ‘std::_Head_base<0, Add3Interface, false>::_M_head_impl’ to be of abstract type ‘Add3Interface’
如何绑定对象的方法?
我希望像
typeid
这样的东西可能会有所帮助:
const auto myFun = std::bind(&(typeid(myAdder)::add3), myAdder, std::placeholders::_1);
但这只会导致各种语法错误,具体取决于我如何放置各种括号。
当然我们可以只使用 lambda:
const auto myFun = [&myAdder] (const auto& arg) { return myAdder.add3(arg); };
但如果可能的话,我更愿意使用
bind
,因为我觉得它代表了我从语义角度试图做得更好的事情。
std::bind
尝试存储其所有参数按值。在本例中,它尝试将 myAdder
复制到 Add3Interface
类型的数据成员中。当然,由于 Add3Interface
是抽象的,所以这是失败的。问题不在于成员函数指针的类型错误。
如果您希望
std::bind
通过引用引用存储的参数,请传递 std::reference_wrapper<T>
而不是 T
。您可以使用便利函数 std::ref
或 std::cref
来构造 std::reference_wrapper
s。
Add3Interface const &myAdder = Add3{};
auto const myFun = std::bind(&Add3Interface::add3, std::ref(myAdder), std::placeholders::_1);
(准确地说,
std::bind
本身根本不专门处理std::reference_wrapper
。它只会将std::reference_wrapper
的副本存储为数据成员,就像存储任何其他参数的副本一样。调用存储函数之前的 std::reference_wrapper
来自标准 INVOKE
操作(本质上是 std::invoke
),std::bind
和其他标准实用程序将“调用可调用”的工作委托给该操作。)