首页 > 解决方案 > 使用 n_copy 将前 n 个元素从一个向量复制到另一个向量的模板函数导致编译错误

问题描述

我正在使用以下模板函数将前 n 个元素从一个向量复制到另一个向量。


// Example program
#include <iostream>
#include <string>
#include <vector>

template <typename Range>
inline std::vector<typename Range::value_type> take(const Range &iRange, int nbrElements) {
  std::vector<typename Range::value_type> result;
  if (nbrElements > iRange.size()) {
    nbrElements = iRange.size();
  }

  std::copy_n(iRange, nbrElements, std::back_inserter(result));

  return result;
}

int main()
{
  std::vector<int> source = { 1, 2, 3, 4, 5, 6, 7,};
  std::vector<int> destination = take(source, 7);

  return 0;
}

问题是我收到以下错误,我不明白为什么:

In instantiation of 'std::vector<typename Range::value_type>
take(const Range&, int) [with Range = std::vector<int>; typename
Range::value_type = int]':
    22:48:   required from here
    10:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    In file included from /usr/include/c++/4.9/algorithm:62:0,
                     from 5:
    /usr/include/c++/4.9/bits/stl_algo.h: In instantiation of '_OIter std::copy_n(_IIter, _Size, _OIter) [with _IIter = std::vector<int>;
_Size = int; _OIter = std::back_insert_iterator<std::vector<int> >]':
    14:62:   required from 'std::vector<typename Range::value_type> take(const Range&, int) [with Range = std::vector<int>; typename
Range::value_type = int]'
    22:48:   required from here
    /usr/include/c++/4.9/bits/stl_algo.h:804:39: error: no matching function for call to '__iterator_category(std::vector<int>&)'
           std::__iterator_category(__first));
                                           ^
    /usr/include/c++/4.9/bits/stl_algo.h:804:39: note: candidate is:
    In file included from /usr/include/c++/4.9/bits/stl_algobase.h:65:0,
                     from /usr/include/c++/4.9/bits/char_traits.h:39,
                     from /usr/include/c++/4.9/ios:40,
                     from /usr/include/c++/4.9/ostream:38,
                     from /usr/include/c++/4.9/iostream:39,
                     from 2:
    /usr/include/c++/4.9/bits/stl_iterator_base_types.h:201:5: note: template<class _Iter> typename
std::iterator_traits<_Iterator>::iterator_category
std::__iterator_category(const _Iter&)
         __iterator_category(const _Iter&)
         ^
    /usr/include/c++/4.9/bits/stl_iterator_base_types.h:201:5: note:   template argument deduction/substitution failed:
    /usr/include/c++/4.9/bits/stl_iterator_base_types.h: In substitution of 'template<class _Iter> typename
std::iterator_traits<_Iterator>::iterator_category
std::__iterator_category(const _Iter&) [with _Iter =
std::vector<int>]':
    /usr/include/c++/4.9/bits/stl_algo.h:804:39:   required from '_OIter std::copy_n(_IIter, _Size, _OIter) [with _IIter =
std::vector<int>; _Size = int; _OIter =
std::back_insert_iterator<std::vector<int> >]'
    14:62:   required from 'std::vector<typename Range::value_type> take(const Range&, int) [with Range = std::vector<int>; typename
Range::value_type = int]'
    22:48:   required from here
    /usr/include/c++/4.9/bits/stl_iterator_base_types.h:201:5: error: no type named 'iterator_category' in 'struct
std::iterator_traits<std::vector<int> >'

标签: c++templatesvectorstl

解决方案


代码有两个问题。第一个是它需要有#include <algorithm>,它定义了std::copy_n,第二个是你需要取begin()of 范围。

修复后,代码如下所示:

// Example program
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>


template <typename Range>
inline std::vector<typename Range::value_type> take(const Range &iRange, int nbrElements) {
  std::vector<typename Range::value_type> result;
  if (nbrElements > iRange.size()) {
    nbrElements = iRange.size();
  }

  std::copy_n(iRange.begin(), nbrElements, std::back_inserter(result));

  return result;
}

int main()
{
  std::vector<int> source = { 1, 2, 3, 4, 5, 6, 7,};
  std::vector<int> destination = take(source, 7);

  return 0;
}

较短的版本

我们可以利用std::vector's range 构造函数来编写一个更短、更高效的take' std::vectors range 构造函数:

template <class Range, class value_t = typename Range::value_type>
std::vector<value_t> take(const Range &range, size_t count) {
  // Ensure count is at most range.size()
  count = std::min(count, range.size()); 
  return std::vector<value_t>(range.begin(), range.begin() + count);  
}

推荐阅读