std::forward_list::remove_if 谓词的要求
Requirements on std::forward_list::remove_if predicates
考虑这段代码:
struct T
{
bool status;
UsefulData data;
};
std::forward_list<T> lst;
lst.remove_if([](T &x) -> bool { return x.status= !x.status; });
即一次性切换状态和删除非活动元素。
根据cppreference,上面的代码似乎是未定义的行为(强调我的):
template< class UnaryPredicate >
void remove_if( UnaryPredicate p );
p
- unary predicate which returns true if the element should be removed.
The signature of the predicate function should be equivalent to the following:
bool pred(const Type &a);
The signature does not need to have const &
, but the function must not modify the objects passed to it.
The type Type
must be such that an object of type forward_list<T,Allocator>::const_iterator
can be dereferenced and then implicitly converted to Type
.
不过,目前的工作草案似乎限制较少(N4659 [forwardlist.ops]):
void remove(const T& value)
template <class Predicate> void remove_if(Predicate pred);
Effects:
Erases all the elements in the list referred by a list iterator i
for which the following conditions hold: *i == value
(for remove()
), pred(*i)
is true
(for remove_if()
). Invalidates only the iterators and references to the erased elements.
Throws:
Nothing unless an exception is thrown by the equality comparison or the predicate.
Remarks:
Stable (20.5.5.7).
Complexity:
Exactly distance(begin(), end())
applications of the corresponding predicate.
标准的其他部分对谓词有额外的限制吗?
我已经在许多编译器上测试了上面的代码,它编译并且似乎按预期工作。我真的需要遍历列表两次吗?
根据你问题下的评论,我的看法是:
forward_list::remove_if
不是算法,因此不属于 [algorithms.requirements].
的规则
[forwardlist.ops] 不限制您在谓词中可以做什么。
forward_list::remove_if
需要对范围内的每个项目恰好应用谓词一次。
因此,在这种情况下修改谓词中的对象是完全合法的,如果有点反社会的话。
编辑:
根据T.C.后来的回答,长期不合法...
委员会的图书馆工作组刚刚将 LWG issue 2998 移动到 "Ready" 状态,基本上确认委员会的意图是第 28 条(算法条款)的相关要求适用于类似的列表操作。这包括 Predicate
不应用任何 non-constant 函数的要求。
一旦通过问题决议(应该在下一次委员会会议上发生),OP 中的代码将正式具有未定义的行为。尽管如此,它通常应该按预期工作,除非有意的敌对实施。如果需要具有保证 well-defined 行为的实现,使用迭代器和 erase_after
.
手动编写一个并不难
考虑这段代码:
struct T
{
bool status;
UsefulData data;
};
std::forward_list<T> lst;
lst.remove_if([](T &x) -> bool { return x.status= !x.status; });
即一次性切换状态和删除非活动元素。
根据cppreference,上面的代码似乎是未定义的行为(强调我的):
template< class UnaryPredicate > void remove_if( UnaryPredicate p );
p
- unary predicate which returns true if the element should be removed. The signature of the predicate function should be equivalent to the following:bool pred(const Type &a);
The signature does not need to have
const &
, but the function must not modify the objects passed to it. The typeType
must be such that an object of typeforward_list<T,Allocator>::const_iterator
can be dereferenced and then implicitly converted toType
.
不过,目前的工作草案似乎限制较少(N4659 [forwardlist.ops]):
void remove(const T& value) template <class Predicate> void remove_if(Predicate pred);
Effects:
Erases all the elements in the list referred by a list iterator
i
for which the following conditions hold:*i == value
(forremove()
),pred(*i)
istrue
(forremove_if()
). Invalidates only the iterators and references to the erased elements.Throws:
Nothing unless an exception is thrown by the equality comparison or the predicate.
Remarks:
Stable (20.5.5.7).
Complexity:
Exactly
distance(begin(), end())
applications of the corresponding predicate.
标准的其他部分对谓词有额外的限制吗?
我已经在许多编译器上测试了上面的代码,它编译并且似乎按预期工作。我真的需要遍历列表两次吗?
根据你问题下的评论,我的看法是:
的规则forward_list::remove_if
不是算法,因此不属于 [algorithms.requirements].[forwardlist.ops] 不限制您在谓词中可以做什么。
forward_list::remove_if
需要对范围内的每个项目恰好应用谓词一次。
因此,在这种情况下修改谓词中的对象是完全合法的,如果有点反社会的话。
编辑:
根据T.C.后来的回答,长期不合法...
委员会的图书馆工作组刚刚将 LWG issue 2998 移动到 "Ready" 状态,基本上确认委员会的意图是第 28 条(算法条款)的相关要求适用于类似的列表操作。这包括 Predicate
不应用任何 non-constant 函数的要求。
一旦通过问题决议(应该在下一次委员会会议上发生),OP 中的代码将正式具有未定义的行为。尽管如此,它通常应该按预期工作,除非有意的敌对实施。如果需要具有保证 well-defined 行为的实现,使用迭代器和 erase_after
.