2013-04-17 42 views
3

我正在学习STL和模板。这是我的问题。我写这个函数的两个迭代器“之间”计算元素的总和:STL容器的C++函数模板专业化

template <typename Iter> double PartialSum(Iter itBegin, Iter itEnd){ 
    if (itBegin == itEnd) return 0.; 
    double dSum = 0; 
    while(itBegin != itEnd){ 
     dSum += (*itBegin); 
     ++itBegin; 
    } 
    return dSum; 
} 

而且这工作正常(我知道我可以使用std::accumulate但这是学习的目的)。现在,我想有相同的功能的std:map但迭代器有不同的工作比在std::vectorstd::list的情况。因此,我想写超载/专用PartialSum。我尝试和失败是这个(小例子):

template <typename T1, typename T2> double PartialSum(std::map<T1,T2>::iterator itBegin{ 
    return 0.; 
} 

这是错误日志:

Main.cpp(42): error: nontype "std::map<_Key, _Tp, _Compare, _Alloc>::iterator [with _Key=T1, _Tp=T2, _Compare=std::less<T1>, _Alloc=std::allocator<std::pair<const T1, T2>>]" is not a type name template <typename T1, typename T2> double PartialSum(std::map<T1,T2>::iterator itBegin){ Main.cpp(83): error: no instance of overloaded function "PartialSum" matches the argument list argument types are: (std::_Rb_tree_iterator<std::pair<const std::string, int>>) std::cout<<"Map partial sum: "<<PartialSum(myMap.begin())<<std::endl; 

由于它是如此简单,我可能不undersatnd一些非常基本的。会很乐意听听你的意见:-)

+2

你不小心删除一半的线路?您尚未完成专业化的参数编写。 –

+0

另一方面,你不能部分专门化一个功能。 (这是一个重载,而不是专门化)你应该使用一个模板函数来调用模板类中的一个静态函数。这可以让你部分专业化。 –

+0

你是什么意思*失败*?编译错误?一些意外的运行时行为 – Gorpik

回答

2

试图以另一种方式来制定。

考虑你有功能

template<typename T> 
T f(){ 
    return T(); 
} 

这是不可能在这里自动获得T,所以你需要把它作为f<T>()。同去同

template <typename T> 
int f(typename type<T>::inner){ 
    // 
} 

举例来说,如果你有

struct type{ 
    typedef int inner; 
} 

很容易看到这里,如果你调用f(0)这是不可能得到T.
你可能会说这是可能得到它在那个特殊的情况下,map,但你将如何定义它?

你应该阅读C++标准阅读哪种类型应该是deducable。


就您的情况,您可以在以下方式

PartialSum<std::string, int>(m.begin()); 

BTW,看来,这地图只是罕见的情况下,你可以尝试做一些更普遍呼吁,将工作与任何迭代器类型。您可能会看到std::accumulate来源获取一些想法。

template<typename _InputIterator, typename _Tp, typename _BinaryOperation> 
inline _Tp 
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init, 
     _BinaryOperation __binary_op) 
{ 
    // concept requirements 
    __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) 
    __glibcxx_requires_valid_range(__first, __last); 

    for (; __first != __last; ++__first) 
__init = __binary_op(__init, *__first); 
    return __init; 
} 
+0

@ RiaD:你能否以某种方式重新配置?我真的很想理解这件事,我发现你的答案中有些东西,但我没有完全理解。 –

+0

@SimonRighley尝试结帐 – RiaD

+0

@ RiaD:正确的点。太棒了,它的工作原理,我明白为什么现在。太感谢了! :) –

-2

当取消引用std::map<T1, T2>::iterator,你会得到一个std::pair<const T1, T2>,其中.first元素是关键,而.second元素的值。

一般结构是这样的:(未测试的代码,甚至未编译)

template <typename T1, typename T2> double PartialSum(std::map<T1,T2>::iterator itBegin, std::map<T1,T2>::iterator itEnd) 
{ 
double dSum = 0; 
while(itBegin != itEnd){ 
    dSum += (itBegin->second); 
    ++itBegin; 
} 
return dSum; 
} 
+0

OP甚至不试图解引用迭代器。 – Gorpik

+0

是的,确切地说。我原来的代码和Marshall Clow发布的代码一样,并没有工作。然后,我将其降至最低限度以缩小问题的根源。 –

1

除此之外,T1和T2是不抵扣的问题,还有就是你错过了typename关键字在从属名称

template<typename T1, typename T2> 
void MyFunction(typename std::map<T1, T2>::iterator it /*, ...*/) 
//    ^^^^^^^^^   

你看到另一个问题,一个从属名称是名称取决于模板参数。的确,理论上可能有这样的类型T1和T2,name map :: iterator不是一个类型,而是一个静态数据成员。编译器将始终假定数据成员,除非您明确指定它是一种类型。

您应该简单地做这样的事

template<class ValueType, class IteratorType, class Func> 
ValueType partialSum(IteratorType first, IteratorType last, ValueType startingValue = ValueType(), Func func = std::plus<ValueType>()) 

,这将覆盖所有的情况。要汇总地图,您需要提供添加两对的func。

+1

没有,这不是主要的问题http://ideone.com/xPZdkE – RiaD

+0

@RiaD:的确,谢谢 –

+0

究竟RIAD,一个错误,当我补充说消失了,但是编译器错误“重载函数没有实例“PartialSum”匹配参数列表“仍然存在。 –