Почему const vector <const pair <... >> выдает ошибку «не может быть перегружен»? - PullRequest
0 голосов
/ 11 января 2019

У меня есть этот простой код:

#include <vector>
#include <string>

void foo(const std::vector<std::pair<std::string, int> > & networks) {
  for (auto p : networks) {
  }
}

void bla(const std::vector<const std::pair<std::string, int> > & networks) {
  for (auto p : networks) {
  }
}

Это приводит к ошибке в bla():

mrvn@frosties:~% g++ -O2 -W -Wall -g -std=gnu++17 -c bla.cc
In file included from /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:33:0,
                 from /usr/include/c++/5/bits/allocator.h:46,
                 from /usr/include/c++/5/vector:61,
                 from bla.cc:1:
/usr/include/c++/5/ext/new_allocator.h: In instantiation of ‘struct __gnu_cxx::new_allocator<const std::pair<std::__cxx11::basic_string<char>, int> >’:
/usr/include/c++/5/bits/allocator.h:92:11:   required from ‘class std::allocator<const std::pair<std::__cxx11::basic_string<char>, int> >’
/usr/include/c++/5/bits/stl_vector.h:79:14:   required from ‘struct std::_Vector_base<const std::pair<std::__cxx11::basic_string<char>, int>, std::allocator<const std::pair<std::__cxx11::basic_string<char>, int> > >::_Vector_impl’
/usr/include/c++/5/bits/stl_vector.h:164:20:   required from ‘struct std::_Vector_base<const std::pair<std::__cxx11::basic_string<char>, int>, std::allocator<const std::pair<std::__cxx11::basic_string<char>, int> > >’
/usr/include/c++/5/bits/stl_vector.h:214:11:   required from ‘class std::vector<const std::pair<std::__cxx11::basic_string<char>, int> >’
bla.cc:10:17:   required from here
/usr/include/c++/5/ext/new_allocator.h:93:7: error: ‘const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = const std::pair<std::__cxx11::basic_string<char>, int>; __gnu_cxx::new_allocator<_Tp>::const_pointer = const std::pair<std::__cxx11::basic_string<char>, int>*; __gnu_cxx::new_allocator<_Tp>::const_reference = const std::pair<std::__cxx11::basic_string<char>, int>&]’ cannot be overloaded
       address(const_reference __x) const _GLIBCXX_NOEXCEPT
       ^
/usr/include/c++/5/ext/new_allocator.h:89:7: error: with ‘_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = const std::pair<std::__cxx11::basic_string<char>, int>; __gnu_cxx::new_allocator<_Tp>::pointer = const std::pair<std::__cxx11::basic_string<char>, int>*; __gnu_cxx::new_allocator<_Tp>::reference = const std::pair<std::__cxx11::basic_string<char>, int>&]’
       address(reference __x) const _GLIBCXX_NOEXCEPT
       ^

Мой вопрос: ПОЧЕМУ?

Примечание: используется g ++ 5.4 и 7.3.

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Это то, что я мог собрать так далеко от стандарта и документации:

std::vector - это контейнер с поддержкой распределителя .

Согласно C ++ 17 (окончательный рабочий проект N4659)

20.5.3.5 Требования к распределителю [allocator.requirements]

Таблица 30 говорит:

T, U, C любой CV-неквалифицированный тип объекта (6,9)

Для std::vector также требуется, чтобы тип элемента был полным и соответствовал требованиям Erasable.

С [container.requirements.general]/15 имеем:

С учетом типа распределителя A и с типом контейнера X, имеющим тип value_type, идентичный T, и тип allocator_-, идентичный allocator_traits<A>::rebind_alloc<T> и дано lvalue m типа A, указатель p типа T*, выражение v типа (возможно, const) T, и значение rv типа T, определены следующие термины.
...
(15.6) - T стирается из X означает, что следующее выражение хорошо сформированный: allocator_traits<A>::destroy(m, p)

Поскольку тип элемента в вопросе квалифицирован const, он не соответствует требованиям.

0 голосов
/ 11 января 2019

Требуется наличие неконстантных значений в векторе:

/ Opt / составитель-исследователь / GCC-8.2.0 / Библиотека / GCC / x86_64-Linux-гну / 8.2.0 /../../../../ включают / C ++ / 8.2.0 / bits / stl_vector.h: 351: 7: ошибка: статический сбой не выполнен из-за требования 'is_same, allocator>, int>> :: type, const pair, allocator>, int>> :: value' "std :: vector должен иметь неконстантный, энергонезависимый тип_значения "

Начнем с требований к вектору до вопроса с распределителем. Тип vector должен поддерживать это:

Требования, предъявляемые к элементам, зависят от фактических операций, выполняемых над контейнером. Как правило, требуется, чтобы тип элемента соответствовал требованиям Erasable, но многие функции-члены предъявляют более строгие требования. Этот контейнер (но не его члены) может быть создан с неполным типом элемента, если распределитель удовлетворяет требованиям полноты распределителя.

Итак, нам нужно что-то, что может быть Erasable и где мы можем сделать:

std::allocator_traits<A>::destroy(m, p);

с m распределителем и p типом, который мы хотим уничтожить. Справедливо. Что еще нам нужно? Для стирания нужен распределитель:

Указывает, что объект данного типа может быть уничтожен данным Allocator.

, что в свою очередь требует T, чтобы быть cv-неквалифицированным :

T, cv-неквалифицированный тип объекта

Таким образом, вы можете иметь std::pair<const string, int>, но не const std::pair<std::string, int>.

В этом отношении сообщение MSVC более четкое, так как оно прямо говорит вам, что неправильно распределен распределитель.

...