I'm learning STL and templates. Here's my problem. I wrote this function calculating sum of elements "between" two iterators:
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;
}
And this works fine (I know I can use std::accumulate
but this is for learning purposes). Now, I would like to have the same functionality for std:map
but iterators there work differently than in the case of std::vector
and std::list
. Therefore, I'd like to write overloaded/specialized PartialSum
. What I tried and failed is this (minimal example):
template <typename T1, typename T2> double PartialSum(std::map<T1,T2>::iterator itBegin{
return 0.;
}
This is the error log:
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;
Since it's so simple I probably don't undersatnd something very fundamental. Would be happy to hear your opinion :-)
Trying to formulate in another way.
Consider you have function
template<typename T>
T f(){
return T();
}
It's impossible here to automatically get T, so you need call it as f<T>()
. Same goes with
template <typename T>
int f(typename type<T>::inner){
//
}
For example, if you have
struct type{
typedef int inner;
}
It's easily to see here, that if you call f(0)
it's impossible to get T.
You may say that's possible to get it in that particular case with map
, but how will you define it?
You should read c++ standard to read which type should be deducable.
In your case you may call in following way
PartialSum<std::string, int>(m.begin());
BTW, It seems, that map is just uncommon case, you may try to do something more general, that will work with any iterator type. You may see std::accumulate
sources to get some ideas.
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;
}
Apart from the problem that T1 and T2 are not deducible, there is another problem that you're missing the typename
keyword on a dependent name
template<typename T1, typename T2>
void MyFunction(typename std::map<T1, T2>::iterator it /*, ...*/)
// ^^^^^^^^^
You see, a dependent name is a name dependent on the template arguments. Indeed, there could theoretically be such types T1 and T2 for which the name map::iterator is not a type but is, say, a static data member. The compiler will always assume a data member unless you explicitly specify that it is a type.
You should simply do something like this
template<class ValueType, class IteratorType, class Func>
ValueType partialSum(IteratorType first, IteratorType last, ValueType startingValue = ValueType(), Func func = std::plus<ValueType>())
And this will cover all cases. To sum a map you will need to provide func that adds two pairs.
When you dereference a std::map<T1, T2>::iterator
, you get a std::pair<const T1, T2>
, where the .first
element is the key, and the .second
element is the value.
General structure like this: (code untested, even uncompiled)
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;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.