简体   繁体   中英

Why can't C++11 move a noncopyable functor to a std::function?

//------------------------------------------------------------------------------
struct A
{
    A(){}
    A(A&&){}
    A& operator=(A&&){return *this;}
    void operator()(){}

private:
    A(const A&);
    A& operator=(const A&);

    int x;
};

//------------------------------------------------------------------------------
int main()
{
    A a;
    std::function<void()> func(std::move(a));
}

'A::A' : cannot access private member declared in class 'A'

It seems like when I capture something by reference or const I can make a non-copyable lambda. However when I do that it actually works to give it to a std::function .

The short answer is that the C++11 specification requires your A to be CopyConstructible to be used with std::function .

The long answer is this requirement exists because std::function erases the type of your functor within the constructor. To do this, std::function must access certain members of your functor via virtual functions. These include the call operator, the copy constructor and the destructor. And since these are accessed via a virtual call, they are "used" whether or not you actually use std::function 's copy constructor, destructor or call operator.

std::function requires functors to be copyable.

This is an arbitrary design decision. Possible alternatives could be:

  • Non-copyable functors are allowed, but attempting to copy the resulting std::function causes a crash/exception.
  • Non-copyable functors are allowed, and std::function s themselves are always non-copyable.
  • ...

It's impossible to only require copyability if the resulting std::function is copied, because it can be copied in a different TU (translation unit).

So, if you ask me, the current behavior is the lesser evil.

It's a bug in Visual Studio. It attempts to ellide a copy (when actually it should be trying to ellide a move), which requires an accessible copy constructor. The best solution is simply to declare the copy constructor/assignment operator and never define them. The class will still be non-copyable but the code will compile, because VS will never attempt to actually call the copy constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM