另一種方式 - 支持每種容器。 (更新支持的元組)
#include <functional>
#include <vector>
#include <iostream>
#include <initializer_list>
#include <algorithm>
#include <tuple>
#include <array>
#include <utility>
#include <type_traits>
#include <numeric>
template<typename F, typename T, typename Container>
auto fold(F fun, T acc, Container&& v)
{
using value_type = std::decay_t<decltype(*std::begin(v))>;
return std::accumulate(std::begin(v), std::end(v), value_type(acc), std::forward<F>(fun));
}
// spceial case for initializer_list as it can't be deduced from a braced initializer
template<typename F, typename T, class V>
auto fold(F fun, T acc, std::initializer_list<V> v)
{
using value_type = std::decay_t<decltype(*std::begin(v))>;
return std::accumulate(std::begin(v), std::end(v), value_type(acc), std::forward<F>(fun));
}
template<typename F, typename T, class Tuple, std::size_t...Is>
auto fold_tuple(F&& f, T acc, Tuple&& tuple, std::index_sequence<Is...>)
{
using expand = int[];
void(expand{
0,
(acc = f(acc, std::get<Is>(std::forward<Tuple>(tuple))), 0)...
});
return acc;
}
template<typename F, typename T, class...Vs>
auto fold(F&& f, T acc, std::tuple<Vs...> const& tuple)
{
using value_type = std::common_type_t<std::decay_t<Vs>...>;
using tuple_type = std::tuple<Vs...>;
constexpr auto element_count = std::tuple_size_v<tuple_type>;
return fold_tuple(std::forward<F>(f), value_type(acc), tuple, std::make_index_sequence<element_count>());
}
template<typename F, typename T, class...Vs>
auto fold(F&& f, T acc, std::tuple<Vs...> && tuple)
{
using value_type = std::common_type_t<std::decay_t<Vs>...>;
using tuple_type = std::tuple<Vs...>;
constexpr auto element_count = std::tuple_size_v<tuple_type>;
return fold_tuple(std::forward<F>(f), value_type(acc), std::move(tuple), std::make_index_sequence<element_count>());
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4 };
std::cout << fold(std::plus<>(), 0, v) << std::endl;
std::cout << fold(std::plus<>(), 0, { 2, 4, 6, 8 }) << std::endl;
std::cout << fold(std::plus<>(), 0, std::array<double, 4>{ 2.1, 4.1, 6.1, 8.1 }) << std::endl;
const double xx[] = { 1, 2, 3, 4, 5.5 };
std::cout << fold(std::plus<>(), 0, xx) << std::endl;
std::cout << fold(std::plus<>(), 0, std::make_tuple(1, 2, 3, 4, 5.5)) << std::endl;
int x = 6;
double y = 7.7;
long long z = 100;
std::cout << fold(std::plus<>(), 0, std::tie(x, y, z)) << std::endl;
}
預期輸出:
10
20
20.4
15.5
15.5
113.7
http://coliru.stacked-crooked.com/a/2eb9df5e4f60258e
你也不回在'情況下沒有過錯:'。打開編譯器警告,也許不要在布爾值上使用'switch'。 'if(v.empty())返回acc;'更具可讀性。 (或'return v.empty()?acc:fold(...') – Ryan
另外,我不是C++專家,但是看起來它每次都複製向量的其餘部分?爲什麼不接受迭代器而不是向量,比如'std :: fill',例如你想要返回'T'而不是'int'。 – Ryan
@RyanThanks你的建議,但是我實際上返回acc以防錯誤,你能解釋一下嗎? – czxyl