简体   繁体   English

使用STL容器的c ++函数模板特化

[英]c++ function template specialization with a STL container

I'm learning STL and templates. 我正在学习STL和模板。 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). 这工作正常(我知道我可以使用std::accumulate但这是出于学习目的)。 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 . 现在,我想为std:map相同的功能,但迭代器的工作方式与std::vectorstd::list的情况不同。 Therefore, I'd like to write overloaded/specialized PartialSum . 因此,我想编写重载/专用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>() . 这里不可能自动获得T,因此您需要将其称为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. 很容易看到这里,如果你调用f(0)就不可能得到T.
You may say that's possible to get it in that particular case with map , but how will you define it? 您可能会说在map中使用该特定情况可以获得它,但您将如何定义它?

You should read c++ standard to read which type should be deducable. 你应该阅读c ++标准来阅读哪些类型应该是可以推断的。


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. 你可能会看到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;
}

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 除了T1和T2不可推导的问题之外,还有另一个问题,即您在从属名称上缺少typename关键字

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. 实际上,理论上可以存在类型为T1和T2的类型,其名称map :: iterator不是类型,而是静态数据成员。 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. 要对地图求和,您需要提供添加两对的func。

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. 当取消引用std::map<T1, T2>::iterator ,就会得到一个std::pair<const T1, T2>其中所述.first元件是关键,和.second元件是值。

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM