функция шаблона, которая использует n_copy для копирования первых n элементов из одного вектора в другой, что приводит к ошибке компиляции - PullRequest
4 голосов
/ 29 апреля 2019

Я использую следующую функцию шаблона для копирования первых 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> >'

Ответы [ 3 ]

5 голосов
/ 29 апреля 2019

Есть две проблемы с кодом. Во-первых, он должен иметь #include <algorithm>, который определяет std::copy_n, а во-вторых, вам нужно взять begin() диапазона.

После исправления код выглядит следующим образом:

// 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, чтобы написать более короткую и очень эффективную версию take, используя конструктор диапазона std::vector:

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);  
}
4 голосов
/ 29 апреля 2019

Вы почти у цели, только первый std::copy_n алгоритм неверен. Измените вызов на

using std::begin;

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

и все должно работать как положено. Кроме того, #include <algorithm> отсутствует, и вы можете предотвратить ненужные выделения, так как знаете размер полученной последовательности:

result.reserve(nbrElements); // before the call to copy_n
3 голосов
/ 29 апреля 2019

Вы можете попробовать что-то вроде этого:

template <typename type>
static std::vector<type> take(const std::vector<type> &iRange, size_t nbrElements) 
{
  if (nbrElements > iRange.size()) 
  {
    nbrElements = iRange.size();
  }
  std::vector<type> result;
  result.insert(result.end(), iRange.begin(), iRange.begin() + nbrElements);
  return result;
}

Edit:

Вы также можете вернуть вектор напрямую:

 return std::vector<type>(iRange.begin(), iRange.begin() + nbrElements);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...