Более общие шаблоны упрощают вывод аргументов шаблона.
Один принцип: часто ошибочно использовать std::function
в качестве параметра шаблонной функции. std::function
- это стирание типа, предназначенное для использования, когда что-то должно хранить какую-то неизвестную вызываемую вещь как определенный c тип. Но шаблоны уже способны обрабатывать любой произвольный вызываемый тип. Поэтому, если мы просто используем шаблонный шаблон generi c typename FuncT
, он может быть выведен для необработанного указателя на функцию, лямбда-выражения или другого класса с непосредственным operator()
.
также сделайте более общий вывод и примите любой входной контейнер вместо vector
, а затем определите по нему T
, если он вообще необходим.
Так что для C ++ 11 я бы переписал это:
// C++20 is adding std::remove_cvref, but it's trivial to implement:
template <typename T>
using remove_cvref_t =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template <typename Container, typename U, typename FuncT>
remove_cvref_t<U> foldLeft(
const Container& data,
U&& initialValue,
const FuncT& foldFn) {
remove_cvref_t<U> accumulator = std::forward<U>(initialValue);
for (const auto& elem : data) {
accumulator = foldFn(std::move(accumulator), elem);
}
return accumulator;
}
template <typename Container, typename FuncT>
auto map(const Container& data, const FuncT& mapper)
-> std::vector<remove_cvref_t<decltype(mapper(*std::begin(data)))>>
{
using T = remove_cvref_t<decltype(*std::begin(data))>;
using ResultT = std::vector<remove_cvref_t<decltype(mapper(std::declval<const T&>()))>>;
ResultT result;
foldLeft(data, std::ref(result), [&mapper] (ResultT &res, const T& value) -> ResultT& {
res.push_back(mapper(value));
return res;
});
return result;
}
См. Рабочую программу для coliru .
В старом map
была одна неприятная вещь: он потенциально копировал вектор результата на каждой итерации. =
в accumulator = foldFn(accumulator, *it);
является самостоятельным назначением, которое может ничего не делать или может выделять новую память, копировать содержимое, затем освобождать старую память и обновлять контейнер. Поэтому вместо этого я изменил U
для foldLeft
в этом случае на std::reference_wrapper
. =
в этом случае все равно будет «перепривязывать» оболочку к тому же объекту, но это, по крайней мере, будет быстрым.
В C ++ 14 и более поздних версиях вы могли бы покончить с поиском T
в пределах map
с использованием обобщенной c лямбды: [&mapper] (std::vector<U>& res, const auto& value)
...