Вы хотите change_if
как простой цикл?
template<typename ForwardIterator, typename UnaryPredicate>
void change_if(ForwardIterator first, ForwardIterator last, UnaryPredicate test, UnaryOperation op) {
for(; first!=last; ++first)
if (test(*first)) *first=op(std::move(*first));
}
или просто напишите вышеуказанный цикл. Я бы посоветовал на самом деле написать change_if
и назвать его, потому что, хотя приведенный выше код короток, я бы нашел, что вызов change_if
будет больше, не менее, ясным, чем просто отбрасывать приведенный выше код.
Я также люблю писать контейнер на основе перегрузок:
template<typename Container, typename UnaryPredicate>
void change_if(Container&& c, UnaryPredicate test, UnaryOperation op) {
for(auto& v : std::forward<Container>(c))
if (test(v)) v=op(std::move(v));
}
, но у меня есть это:
template<typename Iterator>
struct range {
Iterator b, e;
Iterator begin() const { return b; }
Iterator end() const { return e; }
};
template<typename Iterator0, typename Iterator1>
range<typename std::decay<Iterator0>::type> make_range(Iterator0&& b, Iterator1&& e) {
static_assert(
std::is_convertible< Iterator1, typename std::decay<Iterator0>::type >::value,
"end must be compatible with begin iterator type"
);
return { std::forward<Iterator0>(b), std::forward<Iterator1>(e) };
}
, который позволяет мне использовать такие алгоритмы на базе контейнеров с итераторами.
Вы увидите, что у меня есть Container
на основе change_if
? Это действительно диапазон change_if
.
Это называется как:
change_if(myVect, [](int x){return (x%2)==0;}, [](int x){return x/2;});
на контейнере, а не пара итераторов. Однако, если вы хотите изменить первую половину контейнера, это не сработает: на первый взгляд, алгоритмы на основе контейнеров (ну, на основе диапазона) менее полезны.
Но make_range
превращает итераторы в ряд. Таким образом, вы можете:
make_range
заполняет неспособность непосредственно передать 2 итераторы диапазона на основе алгоритмов, связывая два итератора в один range<>
объект. Этот угловой корпус более подробный, но типичный случай (обработки всего контейнера) становится менее подробным.
Плюс, общий вид ошибки (именование другого контейнера для begin
и end
) производится гораздо реже.
Все это заканчивается тем, что является эффективным, или более того, чем версия, основанная на итераторе. И, если вы замените ваши диапазоны с итерируемыми (диапазонами, которые имеют неодинаковые begin
и end
типов итераторов), мой change_if
просто работает
Обратите внимание, что тип умозаключение материал необходим, только если вы на самом деле параметризуя код на типе элемента контейнера , – Sneftel
Как вы используете C++ 14, есть ли еще компиляторы для этого? –
@ JonathanMee Clang 3.4 - это полная версия, и как Visual Studio 2013 November CTP, так и скоро выпущенная gcc 4.9 также поддерживает общие лямбды. Примечание: технически он все еще называется C++ 1y, но в 2014 году многие функции уже здесь! – TemplateRex