我正在尝试编译这段代码,它应该在VS 2017中打印一个向量的总和。
#include <stdio.h>
#include <functional>
#include <vector>
#include <iostream>
template<typename F, typename T, typename K>
//int fold(F fun, T acc, K v) get the same error below
int fold(F fun, T acc, std::vector<K> v)
{
switch (v.empty())
{
case true: return acc;
case false: return fold(fun, fun(*v.begin(), acc), { ++v.begin(), v.end() });
}
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4 };
std::cout << fold([](int a, int b) {return a + b; }, 0, v);
}
产生错误:
错误C2783:'int fold(F,T,std :: vector&lt; K,std :: allocator&lt; K&gt;&gt;)':无法推断'K'的模板参数
为什么K
或int
无法推断std::vector<int>
?如果我更换
template<typename F, typename T, typename K>
int fold(F fun, T acc, std::vector<K> v)
带
template<typename F, typename T>
int fold(F fun, T acc, std::vector<int> v)
然后它成功编译。
答案 0 :(得分:2)
{ ++v.begin(), v.end() }
这被解释为两个元素的初始化列表。选择采用初始化列表的构造函数,而不是采用两个迭代器的构造函数。因此,您尝试使用原始矢量的简化副本调用折叠,但使用两个完全不同的元素的矢量。但是累加器参数与它们不匹配,因此模板参数推断失败。
要修复,请使用明确的结构替换它:
std:::vector<K> { ++v.begin(), v.end() }
另外,在return fold (...)
案例中使用false
。
答案 1 :(得分:2)
另一种方式 - 支持各种容器。 (更新为支持元组)
#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