Неверно, если тип стандартного типа контейнера и тип std:: allocator различны?

Возьмите здесь (который довольно старый):

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

std::list<int, std::allocator<long> >                    // Wrong!

не будет работать.

Вопрос

Правильно ли указано это утверждение (или было ли это когда-либо правильно)? Все тесты, которые я выполнил, работают нормально, независимо от того, что я положил для T в std::allocator. Например, std::vector<int, std::allocator<std::string>> скомпилирован и отлично работает, отталкивая назад и стирая элементы и т.д. (Из того, что я понимаю, std::allocator<std::string>::rebind<int>::other - это волшебство, которое делает эту работу).

Ответ 1

EDIT: в [container.requirements.general] требования к контейнерам, поддерживающим Allocator, указывают, что allocator_type::value_type совпадает с Container::value_type.

Таким образом, он плохо сформировался для передачи в тип распределителя с другим value_type, хотя хотя бы одна реализация просто использует allocator_traits<...>::rebind<value_type> для получения правильного распределителя.

Ответ 2

Я добавляю здесь ответ, чтобы прояснить разницу между неправильным и undefined.

[intro.compliance]/р1:

Набор диагностируемых правил состоит из всех синтаксических и семантических правил в настоящем Международном стандарте, за исключением тех правил, которые содержат явная запись о том, что "никакой диагностики не требуется" или которые описанный как результат поведения undefined.

[defns.ill.formed]:

которая не очень хорошо сформирована

[defns.well.formed]

Программа на С++, построенная в соответствии с правилами синтаксиса, диагностируется семантические правила и правило определения (3.2).

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

  • Он может компилироваться и выполнять, как вы планировали.
  • Он может выдать диагностику.
  • Он может удалить код, который вы написали.
  • Он может переформатировать ближайший диск.

(все, кроме четвертого, обычно происходят на практике)

Undefined поведение очень плохое, и imho, стандарты C и С++ слишком сильно используют эту спецификацию.

Технически, нарушение предложения Requires приводит к поведению undefined.

[res.on.required]/р1:

Нарушение предусловий, указанных в функциях. Требуется: абзац приводит к поведению undefined, если функции Броски: Параметр указывает на исключение исключения, когда предварительное условие нарушены.

Как отмечено MSN, allocator_type::value_type должен быть таким же, как container::value_type, как указано в таблице 99 - Требования к контейнеру с поддержкой ..

allocator_type A       Requires:  allocator_type::value_type 
                                  is the same as X::value_type.

(X обозначает класс контейнера, поддерживающий распределитель, с value_type of T с использованием распределителя типа A)

Итак, такое нарушение, как:

std::list<int, std::allocator<long> >  

- поведение undefined. Итак:

  • может компилироваться и выполняться по вашему желанию.
  • может выдавать диагностику.
  • может удалить код, который вы написали.
  • может переформатировать ближайший диск.

Совсем недавно (в течение нескольких недель после написания этого) libС++ (http://libcxx.llvm.org) начал диагностировать это поведение undefined с помощью static_assert, чтобы вы получить плохие новости как можно скорее.

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

std::list<int, std::allocator<long>>  list1;
std::list<int>                        list2 = list1;  // is specified to not work

т.е. если вы начнете обрабатывать list1 и list2 как эквивалентные типы, потому что std::allocator получает rebind 'd в любом случае, вы будете разочаровываться по дороге, поскольку вы обнаружите, что два списка действительно разные, и не разработаны в любом случае взаимодействовать. Так что лучше всего получить плохие новости как можно скорее, вместо того, чтобы узнать 2 месяца или 2 года спустя, когда вы попытаетесь использовать их в качестве эквивалентных типов.

Возможно, будущий стандарт будет рассматривать list1 и list2 как эквивалентные типы. Это в основном технически возможно (std::is_same, скорее всего, не сработает). Но нет предложений, о которых я слышал в этом направлении. Это направление мне кажется маловероятным. И при static_assert ошибка легко диагностируется. Вместо этого я хотел бы видеть стандартный ход в направлении неправильного формирования этого кода вместо undefined. Самое сложное в этом случае - это раскалывание текста по стандарту, а не реализация std:: lib.