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&&)>.
