std :: set <int * const> не скомпилируется - PullRequest
0 голосов
/ 01 февраля 2019

"const" здесь является причиной проблемы компиляции.Однако, реализовав дерево STL самостоятельно, я не могу понять, почему.

Вот код:

#include <iostream>
#include <set>

int main ()
{
    int a;

    // I want the set to carry the "promise"
    // to keep the pointers constant
    std :: set < int * const > x;

    x . insert ( &a );

    return 0;
}

И вот ошибка:

In file included from /usr/include/c++/7/string:48:0,
                 from /usr/include/c++/7/bits/locale_classes.h:40,
                 from /usr/include/c++/7/bits/ios_base.h:41,
                 from /usr/include/c++/7/ios:42,
                 from /usr/include/c++/7/ostream:38,
                 from /usr/include/c++/7/iostream:39,
                 from demo.cpp:1:
/usr/include/c++/7/bits/stl_function.h: In instantiation of ‘struct std::_Identity<int* const>’:
/usr/include/c++/7/bits/stl_tree.h:2091:29:   required from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_Arg&&) [with _Arg = int* const; _Key = int* const; _Val = int* const; _KeyOfValue = std::_Identity<int* const>; _Compare = std::less<int* const>; _Alloc = std::allocator<int* const>]’
/usr/include/c++/7/bits/stl_set.h:510:48:   required from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(std::set<_Key, _Compare, _Alloc>::value_type&&) [with _Key = int* const; _Compare = std::less<int* const>; _Alloc = std::allocator<int* const>; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<int* const>; std::set<_Key, _Compare, _Alloc>::value_type = int* const]’
demo.cpp:11:18:   required from here
/usr/include/c++/7/bits/stl_function.h:877:7: error: ‘const _Tp& std::_Identity<_Tp>::operator()(const _Tp&) const [with _Tp = int* const]’ cannot be overloaded
       operator()(const _Tp& __x) const
       ^~~~~~~~
/usr/include/c++/7/bits/stl_function.h:873:7: error: with ‘_Tp& std::_Identity<_Tp>::operator()(_Tp&) const [with _Tp = int* const]’
       operator()(_Tp& __x) const

Есть ли «чистый» способ сделать это?(т.е. не обходной путь, как создание «класса указателя» с компаратором для каждой ситуации, подобной этой)

Ответы [ 3 ]

0 голосов
/ 01 февраля 2019

Вы не можете изменять элементы, хранящиеся в std::set поэтому точка является спорным.Он предназначен для хранения элементов в отсортированном порядке, и модификации могут нарушить эту гарантию.Вот почему итераторы (оба std::set<T>::iterator и std::set<T>::const_iterator) оба возвращают константные ссылки .

Нет способа отредактировать элемент, за исключением mutable (или const_cast), и в этом случае вам все еще нужно гарантировать, что порядок остается неизменным.

0 голосов
/ 01 февраля 2019

Более формальный ответ таков: std :: set соответствует требованиям AllocatorAwareContainer :

Набор удовлетворяет всем требованиям контейнера., из обратимого контейнера ([container.requirements]), из ассоциативного контейнера ([associative.reqmts]), и контейнера с распределителем (Таблица 65) .

и в [allocator.requirements] в таблице 33 вы можете прочитать:

T, U, C any cv-unqualified object type ([basic.types])

, где T такой же, как X :: value_type, где X это an allocator class for type T.Это означает, что std::allocator<int * const> не соответствует вышеуказанным требованиям.

Это верно для многих других контейнеров, например, vector, вы можете прочитать больше здесь: Разрешает ли C ++ 11 вектор?

[edit [

Visual Studio дает чуть более описательную ошибку:

C: \ Program Files (x86) \ Microsoft Visual Studio 14.0 \VC \ INCLUDE \ xmemory0 (585): ошибка C2338: Стандарт C ++ запрещает контейнеры с константными элементами, потому что распределитель неправильно сформирован.

с помощью clang вы можете увидеть, что первые строки ошибок направляют заголовки распределителя:

.. / include / c ++ / 5.5.0 / ext / new_allocator.h: 93: 7: ошибка: множественные перегрузки 'address' создают одну и ту же подпись '__gnu_cxx :: new_allocator :: const_pointer (__gnu_cxx:: new_allocator :: const_reference) const noexcept '(он же' int * const * (int * const &) const noexcept ') адрес (const_reference __x) ........

0 голосов
/ 01 февраля 2019

Вот простая программа для демонстрации проблемы, с которой вы сталкиваетесь:

int main(int argc, char ** argv)
{
   int * const a = NULL;
   int * const b = NULL;

   b = a;   // error: cannot assign to variable 'b' with const-qualified type
}

Обратите внимание, что ошибка времени компиляции для изменения значения переменной int * const, потому что переменная считается прочитанной-only.

std::set внутренне имеет ту же проблему - он должен изменить переменные указанного типа, и не может этого сделать, если его указанный тип доступен только для чтения.

Изменениетип const int * вместо этого, вероятно, то, что вы хотите сделать, так как этот тип позволяет указателям при необходимости перезаписывать (не допуская модификаций int, на которые они указывают).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...