То, что я сделал со стандартными алгоритмами обёртывания, - это метаобъект для определения типа контейнера:
namespace detail
{
template <class Range>
struct Iterator
{
typedef typename Range::iterator type;
};
template <class Range>
struct Iterator<const Range>
{
typedef typename Range::const_iterator type;
};
}
Это позволяет обеспечить единственную реализацию, например, find:
template <class Range, class Type>
typename detail::Iterator<Range>::type find(Range& range, const Type& value)
{
return std::find(range.begin(), range.end(), value);
}
Однако это не позволяет называть это временными (я полагаю, я могу жить с этим).
В любом случае, чтобы вернуть изменяемую ссылку на контейнер, очевидно, вы не можете дать никаких гарантий того, что ваша функция делает или не делает с контейнером. Так что этот благородный принцип действительно разрушается: не будьте догматичными.
Я полагаю, что правильность const - это скорее услуга для вызывающего пользователя ваших функций, а не какая-то мера няни, которая должна гарантировать, что вы правильно понимаете свою простую функцию поиска.
Другой вопрос: как бы вы себя чувствовали, если бы я определил следующий предикат, а затем использовал стандартный алгоритм find_if, чтобы увеличить все значения до первого значения> = 3:
bool inc_if_less_than_3(int& a)
{
return a++ < 3;
}
(GCC не останавливает меня, но я не могу сказать, есть ли какое-то неопределенное поведение, связанное с педантичностью).
1) Контейнер принадлежит пользователю. Поскольку разрешение модификации с помощью предиката никоим образом не наносит вред алгоритму, решать, как они его используют, должен сам вызывающий абонент.
2) Это отвратительно !!! Лучше реализовать find_if, как это, чтобы избежать этого кошмара (лучше всего сделать, так как, очевидно, вы не можете выбрать, является ли итератор постоянным или нет):
template <class Iter, class Pred>
Iter my_find_if(Iter first, Iter last, Pred fun)
{
while (first != last
&& !fun( const_cast<const typename std::iterator_traits<Iter>::value_type &>(*first)))
++first;
return first;
}