C++ 将迭代器作为函数参数传递

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20244743/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:59:26  来源:igfitidea点击:

Pass iterator as a function parameter

c++functiontemplatesparametersiterator

提问by Iter Ator

I try to write a function, which will sum the elements of a container. This container can be Vector, List, Queue, etc... That's why I tried templates.

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

Unfortunately I get this error:

不幸的是,我收到此错误:

'C' is not a template

'C' 不是模板

Source:

来源:

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

What do I wrong? How should I fix it?

我怎么了?我该如何解决?

采纳答案by Sebastian Mach

The particular error you get is because you'd need a template template argument:

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

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

However, the standard containers typically have more than just one template argument:

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

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

and it is a bit non-trivial to write such function correctly. You could use variadic template arguments, or you could do like the standard library does, and only specialize as much as you really need:

正确编写这样的函数有点不简单。您可以使用可变参数模板参数,或者您可以像标准库那样做,并且只根据您的实际需要进行专门化:

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

In your case (pretending that your need is not covered by the standard algorithms library already):

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

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


There are some more differences from your original code:

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

  • the new code does not assume a null or a default constructor defined (T s = null;)
  • does not introduce additional iterator (it)
  • uses pre-increment
  • throws an exception when begin==end
  • 新代码不假定定义为 null 或默认构造函数 ( T s = null;)
  • 不引入额外的迭代器 ( it)
  • 使用预增量
  • 开始==结束时抛出异常


If you add an initparameter, you can make it almost noexcept:

如果你添加一个init参数,你几乎可以做到noexcept

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

But only almost, because init += *begincould still throw.

但也只是差不多,因为init += *begin还是会扔。

If you have such signature, you've by the way reproduced the signature of std::accumulate.

如果你有这样的签名,你顺便复制了std::accumulate.

回答by juanchopanza

You could express the whole thing in terms of a iterator type, and use iterator_traitsto get the value_type:

您可以用迭代器类型来表达整个事情,并使用它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;
}

In real life, use std::accumulate:

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

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