Subject: [Boost-bugs] [Boost C++ Libraries] #9449: Boost.MPL min_element bug for equal elements (fix included)
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2013-12-01 22:24:50
#9449: Boost.MPL min_element bug for equal elements (fix included)
-------------------------------------------+-----------------------
Reporter: Rein Halbersma <rhalbersma@â¦> | Owner: agurtovoy
Type: Bugs | Status: new
Milestone: To Be Determined | Component: mpl
Version: Boost 1.55.0 | Severity: Problem
Keywords: min_element, bug |
-------------------------------------------+-----------------------
For equal elements, Boost.MPL `min_element` with a predicate `Pred` does
not satisfy its own requirements of returning the '''first''' element `i`
that satifies `!Pred(j, i)` for all `j`. It turns out that `min_element`
is implemented in terms of `max_element` with the negated predicate
`not_<Pred>`. In turn, `max_element` with its own predicate `Pred` is
required to (and in fact does) return the first element `i` that satisfies
`!Pred(i, j)`.
It is straightforward to see that negating the predicate is a bug. The
current implementation of `min_element` has `less` as its default
predicate, and subsequently calls `max_element` with `greater_equal`,
whereas the requirements indicate that it should use `greater`. This
results in `min_element` returning the '''last''' element of the sequence,
rather than the first.
To get the required semantics, users currently have to supply `less_equal`
to `min_element` as a workaround. The proper fix would be to implement
`min_element` by calling `max_element` with the arguments for the
predicate reversed: `lambda<Pred, _2, _1>`.
See below for a short example that displays the problem and implements the
fix. The program sets up a `vector` of three equal elements. Both
`min_element` and `max_element` are specified to return an iterator to the
first (index 0) element. Instead, `min_element` returns an iterator to the
last (index 2) element. Both the redefined predicate work-around and the
reimplementation of `min_element` fix the problem. The example can be run
from http://coliru.stacked-crooked.com/a/c517d85cbc0aee66
{{{#!c++
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/lambda.hpp>
#include <boost/mpl/less_equal.hpp>
#include <boost/mpl/max_element.hpp>
#include <boost/mpl/min_element.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/vector_c.hpp>
#include <iostream>
using namespace boost::mpl;
template<class Sequence, class Predicate = less<_1,_2>>
struct stable_min_element
:
// mpl::min_element uses max_element<Sequence, not_<Predicate>>
max_element<Sequence, lambda<Predicate, _2, _1>>
{};
int main()
{
using V = vector_c<int, 1, 1, 1>;
using MinIdx = distance<begin<V>::type, min_element<V>::type>;
using LEMinIdx = distance<begin<V>::type, min_element<V,
less_equal<_1, _2> >::type>;
using SMinIdx = distance<begin<V>::type,
stable_min_element<V>::type>;
using MaxIdx = distance<begin<V>::type, max_element<V>::type>;
std::cout << MinIdx::value; // ERROR: prints 2 instead of 0
std::cout << LEMinIdx::value; // 0
std::cout << SMinIdx::value; // 0
std::cout << MaxIdx::value; // 0
}
}}}
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/9449> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:14 UTC