web-dev-qa-db-ja.com

イテレータを関数パラメータとして渡す

コンテナの要素を合計する関数を書こうとしています。このコンテナには、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;
}

何が間違っていますか?どうすれば修正できますか?

10
Iter Ator

発生する特定のエラーは、テンプレートテンプレート引数が必要になるためです。

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の署名を複製したことになります。

6
Sebastian Mach

全体をイテレータ型で表現し、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);
17
juanchopanza