Почему libС++ vector <bool>:: const_reference not bool?

Раздел 23.3.7 Класс vector<bool> [vector.bool], пункт 1 гласит:

template <class Allocator> class vector<bool, Allocator> {
public:
    // types:
    typedef bool              const_reference;
    ...

Однако эта программа не скомпилируется при использовании libС++:

#include <vector>
#include <type_traits>

int
main()
{
    static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}

Кроме того, я отмечаю, что стандарт С++ был последовательным в этой спецификации вплоть до С++ 98. И я также отмечаю, что libС++ последовательно не выполнял эту спецификацию с момента первого введения libС++.

Какова мотивация этого несоответствия?

Ответ 1

Мотивация для этого расширения, которая обнаруживается соответствующей программой и, следовательно, несоответствие, заключается в том, чтобы сделать vector<bool> более похожим на vector<char> на ссылки (const и в противном случае).

Введение

С 1998 года vector<bool> высмеивается как "не совсем контейнер". LWG 96, одна из первых проблем с LWG, запустила дискуссию. Сегодня, спустя 17 лет, vector<bool> остается практически неизменным.

В этой статье приводятся некоторые конкретные примеры того, как поведение vector<bool> отличается от любого другого экземпляра vector, тем самым ущемляя общий код. Однако в одной и той же статье подробно рассматриваются очень хорошие характеристики производительности vector<bool>, если они правильно реализованы.

Сводка: vector<bool> не является плохим контейнером. Это действительно полезно. У него просто плохое имя.

Вернуться к const_reference

Как было показано выше, и подробно описано здесь, что плохо о vector<bool> заключается в том, что он ведет себя по-разному в родовом коде, чем другие vector конкретизации. Вот конкретный пример:

#include <cassert>
#include <vector>

template <class T>
void
test(std::vector<T>& v)
{
    using const_ref = typename std::vector<T>::const_reference;
    const std::vector<T>& cv = v;
    const_ref cr = cv[0];
    assert(cr == cv[0]);
    v[0] = 1;
    assert(true == cv[0]);
    assert(cr == cv[0]);  // Fires!
}

int
main()
{
    std::vector<char> vc(1);
    test(vc);
    std::vector<bool> vb(1);
    test(vb);
}

В стандартной спецификации указано, что объявленный знак // Fires! будет запускаться, но только тогда, когда test запускается с vector<bool>. При запуске с vector<char> (или любым vector кроме bool, когда назначается соответствующий нестандартный T), тест проходит.

Реализация libС++ была направлена ​​на минимизацию негативных последствий того, что vector<bool> ведет себя по-разному в общем коде. Для достижения этой цели нужно сделать vector<T>::const_reference прокси-ссылку, точно так же, как указанную vector<T>::reference, за исключением того, что вы не можете ее назначить. То есть, в libС++, vector<T>::const_reference по существу является указателем на бит внутри vector, а не на копию этого бита.

В libС++ выше test проходит как для vector<char>, так и vector<bool>.

Какую стоимость?

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

Какова мотивация этого несоответствия?

Чтобы дать более качественное поведение клиента libС++ в общем коде и, возможно, после достаточного полевого тестирования, предложите это расширение будущему стандарту С++ для улучшения всей отрасли С++.

Такое предложение может быть представлено в виде нового контейнера (например, bit_vector), который имеет тот же API, что и сегодня vector<bool>, но с несколькими обновлениями, такими как const_reference, обсуждаемые здесь. Затем следует отсрочка (и возможное удаление) специализации vector<bool>. bitset может также использовать небольшую модернизацию в этом отделе, например. add const_reference и набор итераторов.

То есть, задним числом bitset соответствует vector<bool> (который должен быть переименован в bit_vector - или что-то еще), поскольку array соответствует vector. И аналогия должна быть достоверной, независимо от того, говорим ли мы о bool как value_type из vector и array.

Существует несколько примеров функций С++ 11 и С++ 14, которые начинаются как расширения в libС++. Именно так развиваются стандарты. Фактическое продемонстрированное поле позитивный оказывает сильное влияние. Стандартные люди - консервативная группа, когда дело доходит до изменения существующих спецификаций (как и должно быть). Угадав, даже если вы уверены, что правильно догадываетесь, это рискованная стратегия для разработки международно признанного стандарта.