对std :: forward_list :: remove_if谓词的要求

met*_*fox 6 c++ predicate list language-lawyer c++11

考虑以下代码:

struct T
{
bool status;
UsefulData data;
};

std::forward_list<T> lst;

lst.remove_if([](T &x) -> bool { return x.status= !x.status; });
Run Code Online (Sandbox Code Playgroud)

即一次性切换状态和删除非活动元素.

根据cppreference,上面的代码似乎是未定义的行为(强调我的):

template< class UnaryPredicate >
void remove_if( UnaryPredicate p );
Run Code Online (Sandbox Code Playgroud)

p - 一元谓词,如果要删除该元素,则返回true.谓词函数的签名应等效于以下内容:

bool pred(const Type &a);
Run Code Online (Sandbox Code Playgroud)

签名不需要const &,但该函数不能修改传递给它的对象.类型Type必须使得类型的对象forward_list<T,Allocator>::const_iterator可以被解除引用然后隐式转换为Type.

但是,目前的工作草案似乎限制性较小(N4659 [ forwardlist.ops ]):

void remove(const T& value)
template <class Predicate> void remove_if(Predicate pred);
Run Code Online (Sandbox Code Playgroud)

功效:

删除列表迭代器引用的列表中的所有元素,i其中包含以下条件:( *i == valuefor remove()),pred(*i)is true(for remove_if()).仅使迭代器和对已擦除元素的引用无效.

抛出:

除非通过相等比较或谓词抛出异常,否则无效.

备注:

稳定(20.5.5.7).

复杂:

确切地distance(begin(), end())应用了相应的谓词.

标准的其他部分对谓词还有其他限制吗?

我已经在许多编译器上测试了上面的代码,它编译并且似乎按预期工作.我真的需要横向列表两次吗?

T.C*_*.C. 2

委员会的图书馆工作组刚刚将LWG 第 2998 期移至“就绪”状态,基本上确认了委员会的意图是第 28 条(算法条款)的相关要求适用于类似的列表操作。Predicate这包括不应用任何非常量函数的要求。

一旦问题决议被通过(这应该在下一次委员会会议上发生),OP中的代码将正式具有未定义的行为。尽管如此,它通常应该按预期工作,除非故意敌对实施。如果需要一种具有保证良好定义行为的实现,那么使用迭代器和 手动编写一个实现并不太难erase_after