我想编写一个函数,它可以以类型安全的方式在给定的泛型类型上输入迭代器。一个可能的用例是编写像accumulate / map / fold这样的函数:
#include <iterator>
#include <vector>
#include <functional>
template <typename V, typename K>
K accumulate(
std::function<K(K, V)> accumulator,
/* WHAT TYPE DO I PUT HERE */ it,
/* WHAT TYPE DO I PUT HERE */ end,
K initial) {
K sum = initial;
for (; it != end; ++it) {
V item = *it;
sum = accumulator(sum, item);
}
return sum;
}
如何以编译器检查类型和所有好东西的方式执行此操作?
之前曾问过here
答案 0 :(得分:0)
研究标准库容器中使用的模式。问题是你试图明确容器应该定义的许多类型。此外,谨慎使用auto
意味着您根本没有明确声明某些类型。
template <typename C, typename R>
R accumulate(
std::function<R(R, C::value_type)> accumulator,
R initial
) {
auto sum = initial;
for (auto it = C.begin(); it != C.end(); ++it) {
sum = accumulator(sum, *it);
}
return sum;
}
通过使用容器类型作为模板参数,您可以依赖其value_type
定义来确定累加器函数的类型安全性。通过将auto
用于迭代器并使用标准begin()
和end()
方法,您甚至不必明确提及其类型。 (只是为了确定,如果你需要它们,它们是C::iterator
。)
答案 1 :(得分:0)
我想我理解你的问题,我可以想到两种不同的方法,两者都有利有弊:
[1]对迭代器使用第三个模板类型,比如ITER。优点是更简单的代码,适用于更多的集合类型,更少的限制。缺点是,不捕获ITER和V之间的依赖性约束,即ITER必须是迭代类型V的迭代器,即V = ITER :: value_type。
[2]显式调出依赖类型而不是创建新的模板参数。它更准确地捕获依赖类型,减少模板参数的数量。缺点是,它依赖于集合的类型声明,这可能不是标准(如果ITER没有子类型ITER :: value_type,或者命名不同?)。您将在此处使用kewyword typename作为依赖类型。 在这里,编译器可以更好地处理编译错误,但请注意,除非您实际实例化它,否则很难获得有关类型错误的任何反馈。因此,您需要使用2/3具体类型来测试代码。
C ++代码说明了这两种方法。 BTW你为什么使用typename,我认为它应该只是“template&lt; class V,..”。 typename用于依赖类型(例如函数accumulate2)
template <class V, class K, class ITER>
K accumulate1(
std::function<K(K, V)> accumulator,
ITER it,
ITER end,
K initial) {
K sum = initial;
for (; it != end; ++it) {
V item = *it;
sum = accumulator(sum, item);
}
return sum;
}
template <class K, class ITER>
K accumulate2(
std::function<K(K, typename ITER::value_type)> accumulator,
ITER it,
ITER end,
K initial) {
K sum = initial;
for (; it != end; ++it) {
typename ITER::value_type item = *it;
sum = accumulator(sum, item);
}
return sum;
}
string AppendInt(const string& s, int n) {
char buffer [65];
sprintf(buffer, "%s/%d", s.c_str(), n);
return string(buffer);
}
int main(int argc, char* argv[]) {
std::function<string(string,int)> fun =
[](string s, int n) -> string { return AppendInt(s,n); };
string initial = "x";
vector<int> array = {13, 24, 50, 64, 32};
string sum1 = accumulate1(fun, array.begin(), array.end(), initial);
string sum2 = accumulate2(fun, array.begin(), array.end(), initial);
printf("accumulate1 : %s\n", sum1.c_str()); // o/p: x/13/24/50/64/32
printf("accumulate2 : %s\n", sum2.c_str()); // o/p: x/13/24/50/64/32
}