Suppose we have the following hierarchy:
class Add3Interface {
virtual int add3 (const int&) const = 0;
};
class Add3: public Add3Interface {
virtual int add3 (const int& arg) const override {
return arg + 3;
}
};
I want to bind the add3
method so I can use it in things like std::views::transform
.
The following code is fine:
const Add3 myAdder{};
const auto myFun = std::bind(&Add3::add3, myAdder, std::placeholder::_1);
However, in my use case, I don't have access to the concrete type, so I have to write something like this:
auto foo(Add3Interface& myAdder) {
const auto myFun = std::bind(&Add3Interface::add3, myAdder,
std::placeholders::_1);
// ...
}
However, this makes the compiler upset:
/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’
How can I bind my object's method?
I hoped something like typeid
might help:
const auto myFun = std::bind(&(typeid(myAdder)::add3), myAdder, std::placeholders::_1);
But that only led to various syntax errors, which differed depending on how I positioned the various parentheses.
Naturally we could just use a lambda:
const auto myFun = [&myAdder] (const auto& arg) { return myAdder.add3(arg); };
But I'd prefer to use bind
if possible, as I feel it represents what I am trying to do better from a semantic point of view.
std::bind
attempts to store all of its arguments by-value. In this case, it is trying to copy myAdder
into a data member of type Add3Interface
. Of course, as Add3Interface
is abstract, this fails. The issue is not with the member function pointer having the wrong type.
If you want std::bind
to refer to a stored argument by reference, pass a std::reference_wrapper<T>
instead of a T
. You can use the convenience functions std::ref
or std::cref
to construct std::reference_wrapper
s.
auto foo(Add3Interface& myAdder) {
const auto myFun = std::bind(&Add3Interface::add3, std::ref(myAdder),
std::placeholders::_1);
// ...
}
(To be precise, std::bind
doesn't itself handle std::reference_wrapper
specially at all. It will just store a copy of the std::reference_wrapper
as a data member just like it stores a copy of any other argument. The std::reference_wrapper
is correctly unwrapped at the time of the function call because the standard INVOKE
operation that many standard utilities use to invoke callables unwraps it.)