iterator_category и decltype

0

Я работаю через 4-е издание книги Bjarne Stroustrup C++ и столкнулся с проблемой с категориями итераторов. Вот фрагмент кода, который копируется по существу непосредственно из книги, которая не компилируется (глава 5.4.2.1):

#include <algorithm>
#include <iostream>
#include <vector>
#include <forward_list>
#include <iterator>
#include <string>

template<typename Ran>   // for random access iterators
void sort_helper(Ran beg, Ran end, std::random_access_iterator_tag) {
  std::sort(beg, end);
}

template<typename For>   // for forward access iterators
void sort_helper(For beg, For end, std::forward_iterator_tag) {
  std::vector<decltype(*beg)> v{beg,end}; // compilation fails here
  std::sort(v.begin(),v.end());
  std::copy(v.begin(),v.end(),beg);
}

template<typename C>
using Iterator_type = typename C::iterator;

template<typename Iter>
using Iterator_category = typename std::iterator_traits<Iter>::iterator_category;

template<typename C>
void sort(C& c) {
  using Iter = Iterator_type<C>;
  sort_helper(c.begin(), c.end(), Iterator_category<Iter>());
}

void test(std::vector<std::string>& v, std::forward_list<int>& lst) {
  sort(v);
  std::sort(v.begin(),v.end());
  sort(lst);
}

int main(int argc, char * argv[]) {
  std::vector<std::string> sv {"c","b","d","a"};
  std::forward_list<int> fli {3,6,1,7,2,9,4};
  test(sv,fli);
  return 0;
}

Если я прокомментирую содержимое вспомогательной функции, использующей тег итератора forward, все будет компилироваться и работать отлично. Если вы закомментируете содержимое функции, но замените decltype на

std::vector<decltype(beg)> v{beg,end};

который будет компилироваться, но затем компиляция прерывается, как только я пытаюсь включить сортировку, потому что, если я не отменю ссылку, попробуйте использовать сортировку на итераторах вперед. Если я включаю de-ref, ошибка spew трудно разобрать, но похоже, что компилятор пытается обработать аргумент как указатель на int, и он жалуется на нарушения const и тому подобное.

Может ли кто-нибудь дать представление?

Изменение: вот первая ошибка из-за ошибки компилятора:

In file included from small_utils2.cpp:1:
In file included from /usr/bin/../lib/c++/v1/algorithm:594:
/usr/bin/../lib/c++/v1/memory:1656:16: error: 'pointer' declared as a pointer to a reference of type 'int &'
    typedef _Tp*              pointer;
               ^
/usr/bin/../lib/c++/v1/memory:1448:22: note: in instantiation of template class 'std::__1::allocator<int &>' requested here
    typedef typename allocator_type::value_type value_type;
                     ^
/usr/bin/../lib/c++/v1/vector:330:22: note: in instantiation of template class 'std::__1::allocator_traits<std::__1::allocator<int &> >' requested here
    typedef typename __alloc_traits::size_type       size_type;
                     ^
/usr/bin/../lib/c++/v1/vector:484:15: note: in instantiation of template class 'std::__1::__vector_base<int &, std::__1::allocator<int &> >' requested here
    : private __vector_base<_Tp, _Allocator>
              ^
small_utils2.cpp:22:30: note: in instantiation of template class 'std::__1::vector<int &, std::__1::allocator<int &> >' requested here
        std::vector<decltype(*beg)> v{beg,end};
                                    ^
small_utils2.cpp:37:2: note: in instantiation of function template specialization 'sort_helper<std::__1::__forward_list_iterator<std::__1::__forward_list_node<int, void *> *> >' requested here
        sort_helper(c.begin(), c.end(), Iterator_category<Iter>());
        ^
small_utils2.cpp:45:2: note: in instantiation of function template specialization 'sort<std::__1::forward_list<int, std::__1::allocator<int> > >' requested here
        sort(lst);
        ^
  • 0
    В чем ошибка компилятора?
  • 0
    Он длиной 184 строки, поэтому я надеялся, что кто-то может просто скопировать и вставить код (я должен был указать #include, я думаю). Вот некоторые основные моменты ... хммм, я не могу нажать "ввод" в комментарии, которые я вижу.
Теги:
c++11
iterator
decltype

1 ответ

2
Лучший ответ
std::vector<decltype(*beg)> v{beg,end};

*beg возвращает ссылку на объект value_type вектора. Вы получаете ошибку, потому что не можете использовать вектор ссылок.

Вы можете использовать std::remove_reference чтобы отменить ссылки, или вы можете использовать открытый value_type из типа итератора:

std::vector<typename For::value_type> v{beg, end};
//          ^^^^^^^^^^^^^^^^^^^^^^^^
  • 0
    Отлично, это работает отлично. Что ж, похоже, что может быть проблема с std :: remove_reference в stdlibc ++ на моем Mac, но ваш ответ имеет смысл в обоих отношениях. Почему Страуструп сделал то, что сделал?
  • 1
    @GabrielPerdue: он печально известен за небрежность своих примеров.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню