在value_type可移动但不可复制的列表上调用std :: remove_if

时间:2014-02-16 15:47:38

标签: c++ gcc c++11

我正在尝试这样的事情:

class MyClass
{
public:
 explicit MyClass(int) {...};
 MyClass(MyClass&& that) { swap(that); }
private:
 MyClass(const MyClass&); // disabled, pre-C++11 syntax
 MyClass& operator=(const MyClass&); // disabled, pre-C++11 syntax
};

现在我有一个列表,我通过emplace插入它们,我正在尝试做这样的事情。

std::list<MyClass> lst;
std::remove_if(lst.begin(), lst.end(), [&,this](MyClass& mcl) { return mcl.is_foo();});

在gcc 4.6.x上,我不断收到此错误:

In file included from /usr/include/c++/4.6/algorithm:63:0,
             from simple_file_cache.cpp:5:
file_cache_entry.h: In function ‘_FIter std::remove_if(_FIter, _FIter, _Predicate)   
[with_FIter = std::_List_iterator<MyClass>, _Predicate = 
AnotherClass::foo_bar(std::tuple<unsigned int, unsigned int>)::<lambda(MyClass&)>]’:
anotherclass.cpp:225:11:   instantiated from here
anotherclass.h:68:18: error: ‘MyClass& MyClass::operator=(const MyClass&)’ is private
/usr/include/c++/4.6/bits/stl_algo.h:1149:13: error: within this context
make: *** [simple_file_cache.o] Error 1

为什么要寻找复制构造函数?

1 个答案:

答案 0 :(得分:4)

您需要为remove_if定义移动任务 - 运算符。如果存在用户声明的副本赋值运算符(或用户声明的副本ctor,或者dtor,或者......),则不会隐式声明它。

以下似乎是在g ++ 4.6下编译的:

#include <list>
#include <algorithm>

class MyClass
{
public:
 explicit MyClass(int) {};
 MyClass(MyClass&&) {}
 MyClass& operator=(MyClass&&) {return *this;}
private:
 MyClass(const MyClass&); // disabled, pre-C++11 syntax
 MyClass& operator=(const MyClass&); // disabled, pre-C++11 syntax
};

int main()
{
    std::list<MyClass> lst;

    // compiles, but why use that:
    //std::remove_if(lst.begin(), lst.end(), [](MyClass& mcl) { return true; });

    // also compiles, makes more sense to me (but that depends on the context):
    lst.remove_if([](MyClass& mcl) { return true; });
}

请注意,如果可以保证,则应考虑同时移动noexcept

Live example


如果要将列表的某些元素移动到列表的末尾,我宁愿使用基于splice的算法。例如,

template<class value_type, class allocator, class F>
//typename std::list<value_type, allocator>::iterator
void
move_to_end_if(std::list<value_type, allocator>& list, F condition)
{
    if(list.size() < 2) return; //list.end();

    auto const former_last = std::prev(list.end());

    for(auto i = list.begin(); true; ++i)
    {
        if(condition(*i))
        {
            list.splice(list.end(), list, i);
        }

        if(i == former_last) break;
    }

    // return ????;
}

这会将满足条件的所有元素移动到列表的实际(当前)末尾,保留它们的相对顺序。

注意:算法应该将迭代器返回到未移动序列的末尾,或list::end()。还没有找到一种优雅的方式来做到这一点。