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