My question concerns the line of code below marked with the // WHY???
comment.
Below is a toy example of some code I was expecting to break: a std::function
variable is assigned a function pointer whose parameters almost match, but differ in const
and &
. It didn't break. I've figured out why it works -- there's a copy constructor call added by the compiler that I didn't expect.
My question is: why does C++ allow this case? What is the use-case that made the C++ committee decide this should work (as opposed to the compiler rejecting this assignment)?
#include <memory>
#include <functional>
#include <iostream>
class Thing {
public:
Thing(int count) : count_(count) {}
int count_;
};
typedef std::function<void(const Thing&)> ConstByRefFunction;
void DoThingByValue(Thing event) { event.count_ += 5; }
int main() {
Thing thing(95);
ConstByRefFunction func = DoThingByValue; // WHY???
// The following line copies thing even though anyone looking at
// the signature of ConstByRefFunction would expect it not to copy.
func(thing);
std::cout << thing.count_ << std::endl; // still 95
return 0;
}
The signature you specify in the std::function
template is the signature used for the std::function
's operator()
overload, NOT the signature used for the target that the operator()
calls.
You can assign any target to std::function
which is Callable using the parameters of the operator()
. In your example, DoThingByValue()
is an acceptable target because a const Thing&
parameter can be passed by value to a Thing
parameter (thus invoking the Thing
copy constructor), no different than if you were doing something like this:
void DoThingByValue(Thing event) {
...
}
void DoThingByConstRef(const Thing &event) {
DoThingByValue(event); // <-- COPY HERE
}