Рассмотрим простое обобщение станд :: преобразования я написал для N входных итераторов:Обобщение станд :: преобразование
#include <iostream>
#include <vector>
#include <string>
template <typename InputIterator, typename OutputIterator, typename NaryOperator, typename... InputIterators>
OutputIterator transform (InputIterator first, InputIterator last, OutputIterator result,
NaryOperator op, InputIterators... iterators) {
while (first != last) {
*result = op(*first, *iterators++...);
++result; ++first;
}
return result;
}
int main() {
const std::vector<int> a = {1,2,3,4,5};
const std::vector<double> b = {1.2, 4.5, 0.6, 2.8, 3.1};
const std::vector<std::string> c = {"hi", "howdy", "hello", "bye", "farewell"};
std::vector<double> result(5);
transform (a.begin(), a.end(), result.begin(),
[](int i, double d, const std::string& s)->double {return i + d + s.length();},
b.begin(), c.begin());
for (double x : result) std::cout << x << ' '; // 4.2 11.5 8.6 9.8 16.1
}
То, что я хочу сделать сейчас, это позволит векторы a
, b
, c
иметь различные длины (и аргумент InputIterator last
можно удалить), и в этом случае transform
будет продолжать преобразование до тех пор, пока не будет использован самый длинный вектор, используя значения по умолчанию для более коротких векторов.
Я думал, что это будет просто изменение размеров всех коротких контейнеров в функции transform
, но аргументы transform
не дают информации о том, сколько времени все контейнеры. Есть ли способ вычислить в пределах transform
, как долго каждый из контейнеров, тем самым получая максимальную длину и тем самым заполняя значения по умолчанию для более коротких контейнеров? В идеале, используя только синтаксис:
transform (OutputIterator result, NaryOperator op, InputIterators... iterators);
Обновление: После идеи Раманы, я имею в виду использовать что-то вроде:
template <typename OutputIterator, typename NaryOperator, typename... InputIterators>
OutputIterator transform (OutputIterator result, NaryOperator op, InputIterators... first, InputIterators... last) {
while (true) {
*result = op((first == last ?
typename std::iterator_traits<InputIterators>::value_type() : *first++)...);
++result;
}
return result;
}
Но
transform (result.begin(),
[](int i, double d, const std::string& s)->double {return i + d + s.length();},
a.begin(), b.begin(), c.begin(), a.end(), b.end(), c.end());
не компилируется. Я думаю, потому что компилятор не знает, где начинается last...
.
Так что я попытался это следующее:
template <typename OutputIterator, typename NaryOperator, typename... InputIteratorsPairs>
OutputIterator transform (OutputIterator result, NaryOperator op, InputIteratorsPairs... pairs) {
while (true) {
*result = op((pairs.first == pairs.second ?
typename InputIteratorsPairs::first_type() : *pairs.first++)...);
++result;
}
return result;
}
Но
transform_ (result.begin(),
[](int i, double d, const std::string& s)->double {return i + d + s.length();},
std::make_pair(a.begin(), a.end()), std::make_pair(b.begin(), b.end()), std::make_pair(c.begin(), c.end()));
не компилируется либо (и мне не нравится синтаксис в любом случае).
['std :: distance()'] (http://en.cppreference.com/w/cpp/iterator/distance)? –
Как насчет переопределения итераторов ++, чтобы остановить продвижение, когда оно находится в конце, и вернуть значение по умолчанию для контейнера? –
@ Парамагнитный круассан. Вы имеете в виду вызов 'iterators ++ ..', пока какой-либо из них не достигнет конца, а затем вычислите длину, используя std :: distance? Как узнать, когда достигается «конец»? – prestokeys