Вероятно, есть что-то встроенное для повышения, но вот моя хакерская попытка написать собственный итератор:
template <typename T, typename FN>
struct transform_iterator {
transform_iterator(T &t, FN fn)
: _t{t}
, _fn{std::move(fn)} { }
transform_iterator<T, FN>& operator * () { return *this; }
transform_iterator<T, FN>& operator ++ () { return *this; }
template <typename V>
transform_iterator<T, FN>& operator = (V const &v) {
_t.push_back(_fn(v));
return *this;
}
T &_t;
FN _fn;
};
Это возьмет функцию и выполнит ее всякий раз, когда что-то пытается назначить итератору (я думаю , как обычно работают такие вещи, как back_inserter
). Тривиальная вспомогательная функция может создавать итераторы:
template <typename T, typename FN>
auto make_transform_iterator(T &t, FN fn) {
return transform_iterator<T, FN>{t, std::move(fn)};
};
Наконец, iterator_traits
должен быть специализированным, поэтому transform_iterator
будет работать с алгоритмами.
namespace std {
template <typename T, typename FN>
struct iterator_traits<transform_iterator<T, FN>> {
using value_type = typename T::value_type;
};
}
В iterator_traits
должны быть установлены другие типы, но этого было достаточно для моего тестирования; Ваш пробег будет варьироваться.
Мой main
выглядит так:
int main() {
std::vector<int> xx{1, 2, 3};
std::vector<int> yy{1, 3, 5};
std::vector<int> diff;
auto ba = make_transform_iterator(diff, [](auto v) { return v + 10; });
std::set_difference(std::begin(xx), std::end(xx),
std::begin(yy), std::end(yy),
ba);
for(auto const &v: diff) {
std::cout << v << '\n';
}
return 0;
}
Вы можете расширить это для работы с общими итераторами вывода вместо просто типов, которые поддерживают push_back
.