为什么remove_if(...,lambda)表达式需要赋值运算符?

Hel*_*ein 2 c++ lambda stl operator-overloading c++11

我有这个代码(简化):

std::vector<Session> sessions;
// ...
std::remove_if( sessions.begin(), sessions.end(), 
   [] (const Session& s) {
      return false;
   }
);
Run Code Online (Sandbox Code Playgroud)

当我编译它(在Visual Studio 2013 Update 1中)时,我收到以下错误:

algorithm(1759): error C2280: 'Session &Session::operator =(const Session &)' : attempting to reference a deleted function
   Session.h(78) : see declaration of 'Session::operator ='
Run Code Online (Sandbox Code Playgroud)

的确,我operator=Session课堂上删除了这样的内容:

Session& operator= (const Session& that) = delete;
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么remove_if使用lambda表达式需要赋值运算符?一个Session对象分配给另一个对象在哪里?

更新:正如@nosid和@Praetorian所解释的那样,remove_if需要移动或复制构造函数和赋值运算符.根据C++ 11标准,移动构造函数/赋值运算符应该由编译器自动生成.不幸的是Visual Studio 2013不这样做.由于类不可复制remove_if也无法求助于复制,因此编译器显示错误.我通过手动实现移动构造函数和移动赋值运算符来修复它.

Pra*_*ian 7

std::remove_if 要求通过解除引用迭代器获得的对象是MoveAssignable(第25.3.8/1节).但是因为你明确地使用delete了复制赋值运算符,所以移动赋值运算符也是隐含的deleted.

假设Session可以支持移动语义,您可以remove_if通过定义移动赋值运算符来开始工作.例如,简单地添加defaulted移动赋值运算符就足以解决当前的问题(请注意,您可能无法依赖于编译器生成的版本,并且可能必须自己定义一个).

Session& operator=(Session&&) = default;
Run Code Online (Sandbox Code Playgroud)

现场演示


VS2013不支持默认的移动构造函数/赋值运算符,因此在您的情况下,您将被迫实现一个.


nos*_*sid 5

该错误不是由lambda表达式引起的.lambda表达式很好,如果你替换remove_ifall_of:

// OK
std::all_of(_sessions.begin(), _sessions.end(), 
    [](const Session& session) { return false; });
Run Code Online (Sandbox Code Playgroud)

该错误是由算法引起的std::remove_if.通过移动范围内的元素来完成移除,使得不被移除的元素出现在范围的开头.因此,需要复制或移动分配.

对于需要复制或移动赋值操作的其他算法,您将看到相同的错误消息,即使它们在没有lambda表达式的情况下使用也是如此.这是一个例子:

// ERROR: Session& operator=(const Session&) is private
std::move(std::next(_sessions.begin()), _sessions.end(), _sessions.begin());
Run Code Online (Sandbox Code Playgroud)