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,上面的代码似乎是未定义的行为(强调我的):
Run Code Online (Sandbox Code Playgroud)template< class UnaryPredicate > void remove_if( UnaryPredicate p );
p- 一元谓词,如果要删除该元素,则返回true.谓词函数的签名应等效于以下内容:Run Code Online (Sandbox Code Playgroud)bool pred(const Type &a);签名不需要
const &,但该函数不能修改传递给它的对象.类型Type必须使得类型的对象forward_list<T,Allocator>::const_iterator可以被解除引用然后隐式转换为Type.
但是,目前的工作草案似乎限制性较小(N4659 [ forwardlist.ops ]):
Run Code Online (Sandbox Code Playgroud)void remove(const T& value) template <class Predicate> void remove_if(Predicate pred);功效:
删除列表迭代器引用的列表中的所有元素,
i其中包含以下条件:(*i == valueforremove()),pred(*i)istrue(forremove_if()).仅使迭代器和对已擦除元素的引用无效.抛出:
除非通过相等比较或谓词抛出异常,否则无效.
备注:
稳定(20.5.5.7).
复杂:
确切地
distance(begin(), end())应用了相应的谓词.
标准的其他部分对谓词还有其他限制吗?
我已经在许多编译器上测试了上面的代码,它编译并且似乎按预期工作.我真的需要横向列表两次吗?
委员会的图书馆工作组刚刚将LWG 第 2998 期移至“就绪”状态,基本上确认了委员会的意图是第 28 条(算法条款)的相关要求适用于类似的列表操作。Predicate这包括不应用任何非常量函数的要求。
一旦问题决议被通过(这应该在下一次委员会会议上发生),OP中的代码将正式具有未定义的行为。尽管如此,它通常应该按预期工作,除非故意敌对实施。如果需要一种具有保证良好定义行为的实现,那么使用迭代器和 手动编写一个实现并不太难erase_after。