In this code snippet, I don't understand why there is an error below:
#include <functional>
class Foo {};
int main()
{
std::function<void(Foo)> func;
std::function<void(Foo)> f1;
std::function<void(Foo const&)> f2;
std::function<void(Foo&)> f3;
func = f1;
func = f2;
func = f3; // error: no match for ‘operator=’ (operand types are ‘std::function<void(Foo)>’ and ‘std::function<void(Foo&)>’)
return 0;
}
So, I'm wondering why is it OK to use a function taking the parameter by constant reference, but not as a non-constant reference?
Can somebody kindly explain it to me?
Thanks in advance!
CodePudding user response:
Neither f1
nor f2
can modify their argument, f3
however can. Allowing a function that was bound to f3
to be called through f1
or f2
would either break const-correctness or allow to change a temporary and thus break semantical correctness.
How the implementation guarantees that these are not broken is secondary. The behaviour you describe must not work.
CodePudding user response:
std::function
uses std::forward
to pass parameters from its operator()
to its underlying callable. That is, an abbreviated version of std::function
looks something like this:
template <typename Ret, typename... Args>
class function
{
public:
Ret operator()(Args... args)
{
return get_callable()(std::forward<Args>(args)...);
}
// Other stuff
};
That means that any parameters that are non-reference types will be passed to the underlying callable as rvalues. References to non-const cannot bind to rvalues, and so a std::function<void(Foo)>
is incompatible with std::function<void(Foo&)>
, but it is compatible with both std::function<void(Foo const&)>
and std::function<void(Foo&&)>
.