Передать итератор как параметр функции

Я пытаюсь написать функцию, которая будет суммировать элементы контейнера. Этот контейнер может быть вектором, списком, очередью и т. д... Вот почему я пробовал шаблоны.

к сожалению, я получаю эту ошибку:

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

что я не так? Как это исправить?

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

и это немного нетривиально, чтобы написать такую функцию правильно. Вы можете использовать аргументы шаблона variadic, или вы можете делать, как стандартная библиотека, и специализироваться только столько, сколько вам действительно нужно:

// <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)
  • использует pre-increment
  • создает исключение, когда 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.


вы можете выразить все это в терминах типа итератора и использовать 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::накапливать:

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