【问题标题】:Pass iterator as a function parameter将迭代器作为函数参数传递
【发布时间】:2013-12-13 05:29:57
【问题描述】:

我尝试编写一个函数,它将对容器的元素求和。这个容器可以是Vector、List、Queue等……这就是我尝试模板的原因。

很遗憾,我收到了这个错误:

'C' 不是模板

来源:

#include <iostream>
#include <vector>

using namespace std;

template<class C, typename T>
T sum( C<T>::iterator begin, C<T>::iterator end ) {
    T s = null;

    for (C<T>::iterator it = begin; it != end; it++) {
        s += *it;
    }

    return s;
}

int main()
{
    vector<int> v = {5, 9, 0, 11};

    cout << sum(v.begin(), v.end()) << endl;

    return 0;
}

我做错了什么?我该如何解决?

【问题讨论】:

  • 如果您想利用 C++ STL 的优势,可以使用accumulate

标签: c++ function templates parameters iterator


【解决方案1】:

您可以用迭代器类型来表达整个事情,并使用iterator_traits 来获取 value_type:

#include <iterator>

template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type 
sum(Iterator begin, Iterator end)
{
  using value_type = typename std::iterator_traits<Iterator>::value_type;
  value_type s = value_type();
  for (Iterator it = begin; it != end; it++) {
    s += *it;
  }
  return s;
}

在现实生活中,使用std::accumulate

int sum = std::accumulate(v.begin(), v.end(), 0);

【讨论】:

  • +1。但肯定是std::iterator_traits&lt;Iterator&gt;::value_type s;
【解决方案2】:

您得到的特定错误是因为您需要一个模板模板参数:

template<template <typename> class C, typename T>
//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
T sum( C<T>::iterator begin, C<T>::iterator end )

但是,标准容器通常不止一个模板参数:

template < class T, class Alloc = allocator<T> > class vector

正确地编写这样的函数有点不重要。你可以使用可变参数模板参数,或者你可以像标准库那样做,只在你真正需要的时候专门化:

// <algorithm>
namespace std {
    template <class RandomAccessIterator>
    void sort (RandomAccessIterator first, RandomAccessIterator last);
}

在您的情况下(假设您的需求尚未包含在标准算法库中):

template <typename Iterator>
auto sum(Iterator begin, Iterator end) 
-> decltype(*begin+*begin) // the type of summing two of them
{
    if (begin == end) throw std::logic_error("....");
    auto s = *begin;
    ++begin;
    for (; begin != end; ++begin) {
        s += *begin;
    }
    return s;
}

与您的原始代码还有一些不同之处:

  • 新代码不假定定义了 null 或默认构造函数 (T s = null;)
  • 不引入额外的迭代器 (it)
  • 使用预增量
  • 当 begin==end 时抛出异常

如果你加一个init参数,你可以让它几乎noexcept

template <typename Iterator, typename T>
T sum(Iterator begin, Iterator end, T init)
{
    for (; begin!=end; ++begin)
        init += *begin;
    return init;
}

但只有差不多,因为init += *begin 仍然可以抛出。

如果你有这样的签名,顺便说一下,你已经复制了std::accumulate的签名。

【讨论】:

  • 是否可以像这样传递迭代器指针?,即。模板 T sum(Iterator *begin, Iterator *end, T init) { .... } ?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2018-09-30
相关资源
最近更新 更多