[英]Accept templated parameter of stl_container_type<string>::iterator
[英]Pass Templated iterator for STL Container
对于我的C ++类(尚未涵盖Boost)的练习,我在编写模板化方法以接受两个迭代器来汇总STL容器中的数值时遇到问题。
请考虑以下示例:
#include <iostream>
#include <iterator>
#include <vector>
template<typename T>
double Sum(const T & c) {
return 42.0; // implementation stubbed
}
// need help writing this method signature to accept two iterators
template<typename T>
double Sum(const typename T::const_iterator & begin,
const typename T::const_iterator & end) {
return 43.0; // another implementation stub
}
int main() {
std::vector<double> v;
v.push_back(3.14);
v.push_back(2.71);
v.push_back(1.61); // sums to 7.46
std::cout << Sum(v) << ' ' // line 23
<< Sum(v.begin(), v.end()) // line 24
<< '\n';
}
我希望这段代码输出42 43
,但它无法编译。
g ++给我的错误是:
test_exercise2.cpp: In function ‘int main()’:
test_exercise2.cpp:24: error: no matching function for call to ‘Sum(__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >, __gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >)’
如果我注释掉第24行,我会得到42
作为输出,正如预期的那样。
无论第二个模板化方法是否存在,我都会得到相同的错误消息,因此由于某种原因,它无法将第24行的调用解析为我编写的第二个方法。
对于接受两个迭代器的方法,我必须具有什么签名?
我之所以坚持这一点,是因为我需要支持对std::map<K, V>
的第二个元素进行求和。 这将需要再调用两次->second
而不是解除引用迭代器:
1. template<typename K, typename V> double Sum(const std::map<K, V> & m);
(我对这个没问题)
2.另一个涉及地图上的迭代器。
我觉得如果我能弄清楚如何为std::list
和std::map
指定迭代器的传递,我将能够编写std::map
的方法。 我对使用模板模板的解决方案没问题。
编辑:问题的准确措辞(省略非缴费句子)。
来自“上一个练习”的容器是std::vector<double>
, std::list<double>
, std::map<std::string, double>
。
创建一个名为Sum()的模板函数,它接受模板参数T作为输入并返回一个double。 template参数将是一个容器。
- 在实现中为结束获取一个迭代器(T :: const_iterator)。 然后创建一个循环,迭代容器T并添加所有值。 最后归还总和。
- 在主程序中,为上一个练习中的不同容器调用Sum()函数。
创建的Sum()函数计算完整容器的总和。 还要创建一个Sum()函数来计算两个迭代器之间的总和。 然后该函数使用模板参数作为迭代器类型,并接受两个迭代器,即开始和结束迭代器。
你这太复杂了。 你想要一对任何类型的迭代器? 嗯,这就像两个参数一样简单,任何类型。
template<typename Iterator>
double Sum(const Iterator& begin,
const Iterator& end) {
return 43.0; // another implementation stub
}
问题解决了。
顺便说一下,从C ++标准库中获取提示:如果你不能取消引用迭代器,那么让用户提供一个函数来从迭代器中获取值。 不要特殊情况std::map
因为明天有std::unordered_map
和boost::multimap
之后的那一天以及各种各样的乐趣。 而如果我想你总结从按键 std::map
,而不是价值?
您的硬编码案例有点复杂。 一对必须来自std::map
的迭代器? 如果没有明确的模板参数,甚至不确定。
template<typename K, typename V, typename Comp, typename Alloc>
double Sum(
const std::map<K, V, Comp, Alloc>& map
) { ... }
请注意,我特意说它必须是std::map
实例化。 这允许编译器推导出参数。 从这里,您可以访问迭代器。
正如DeadMG所说,简单的方法是模板化迭代器的类型。 另一方面,通用约定是按值传递迭代器:
template <typename Iterator>
double Sum( Iterator begin, Iterator end );
至于为什么原始代码不起作用,问题是容器的类型是不可推导的:
template <typename T>
double Sum( T::const_iterator begin, T::const_iterator end );
Sum( v.begin(), v.end() ); // [*] Assume v == const std::vector<double>&
当编译器尝试推断Sum
的参数类型时,它只能看到v.begin()
和v.end()
返回的类型,它们是迭代器 。 从该类型,它无法猜测容器的类型。 为了能够确定类型T
是什么,它必须测试所有非模板类型,并生成模板类型的所有无限可能实例化,以查看它们是否具有与v.begin()
的类型匹配的嵌套类型const_iterator
v.end()
。 因为那是不可能实现的,语言首先禁止它。
除此之外,与注释[*]相关 ,即使类型可以推断,也会对函数的参数执行重载解析,而不是以后如何使用表达式。 在你的程序中, .begin()
的参数是std::vector<double>
非const lvalue 。 因为它不是const,所选择的重载将产生一个非const迭代器(即使在你想要调用的函数中,也不需要读取它)。
将std::list
中的迭代器与std::map
迭代器进行对比时的区别特征是后者具有一对类型作为其value_type
。 也就是说,给定std::map<K, V>
然后std::map<K, V>::value_type
和std::iterator_traits<std::map<K, V>::iterator>::value_type
是std::pair<const K, V>
。
因此,我建议您的Sum
模板接受任何迭代器,但它不对迭代器(即*it
)给出的元素进行操作,而是对'view': element(*it)
。 现在你可以注意确保element
在面对一对时“做正确的事”。
作为提示,您可以将Sum
声明为以下(使用一些元编程来正确获取返回类型):
namespace result_of {
// Second template parameter is an implementation detail
template<
typename Iterator
, typename ValueType = typename std::iterator_traits<Iterator>::value_type
>
struct Sum {
// general case: sum over the value type directly
typedef ValueType type;
};
// If an iterator admits an std::pair as its value_type then we end up here
template<typename Iterator, typename Key, typename Value>
struct Sum<Iterator, std::pair<Key, Value> > {
// special case: sum over the second type of the value
typedef Value type;
};
} // result_of
template<typename Iterator>
typename result_of::Sum<Iterator>::type Sum(Iterator begin, Iterator end);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.