Home > Blockchain >  Why can std::function<void(T)> get assigned to std::function<void(T const&)> but not std
Why can std::function<void(T)> get assigned to std::function<void(T const&)> but not std

Time:08-24

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

  • Related