Конструктор преобразования варианта С++ с bool

В cppreference (4) конструктор преобразования описывается следующим образом:

Преобразующий конструктор. Создает вариант, содержащий альтернативный тип T_j, который был бы выбран разрешением перегрузки для выражения F(std::forward<T>(t)), если бы была перегрузка воображаемой функции F(T_i) для всех T_i из Types... в области видимости одновременно, за исключением того, что:

  • Перегрузка F(T_i) рассматривается только в том случае, если объявление T_i x[] = { std::forward<T>(t) }; допустимо для некоторой выдуманной переменной x;
  • Если T_i является (возможно, cv-квалифицированным) bool, F(T_i) рассматривается только в том случае, если std:remove_cvref_t<T> также является bool.

Меня особенно интересует второй пункт, касающийся bool. В примере сказано, что:

std::variant<std::string, bool> y("abc"); // OK, chooses string; bool is not a candidate

Теперь я протестировал тот же код с clang 7.0.0 (godbolt), gcc.8.2 (godbolt) и VS2017. И мне интересно, почему содержащийся альтернативный тип - bool (для всех трех компиляторов), а не std::string, как описано в cppreference. Это ошибка в стандартных библиотеках всех трех компиляторов?

Я также нашел следующий документ: P0608R3 . Означает ли это, что модификации (два пункта), которые перечислены в списках предпочтений, только предложены, но еще не являются частью официального стандарта?


person Kilian    schedule 01.02.2019    source источник
comment
Из того, что я могу сказать, cppreference обновил страницу, но компиляторы еще не догнали. Я оставлю это для тех, кто действительно обязательно ответит.   -  person NathanOliver    schedule 01.02.2019
comment
Похоже на TC обновил страницу.   -  person YSC    schedule 01.02.2019


Ответы (2)


P0608R3 был принят в Сан-Диего. Его формулировка была применена к рабочему проекту — вы можете увидеть новую формулировку в [variant.ctor ]/12.

Как часть этого изменения, мотивирующий пример:

variant<string, bool> x = "abc";

Теперь содержит string (в С++ 20), тогда как раньше он содержал bool (в С++ 17). Значение этого примера меняется между стандартными версиями.

Просто ни одна из стандартных библиотек еще не реализовала это изменение. Это очень недавно. Он указан как неполный как в libstdc++, так и в libc++. Но, как вы можете видеть, в C++20 тоже есть масса возможностей, которые еще не реализованы. Хорошая новость в том, что еще только начало 2019 года, и времени еще предостаточно.

person Barry    schedule 01.02.2019
comment
Было ли это применено задним числом к ​​С++ 17, как указано на странице cppreference? - person NathanOliver; 01.02.2019
comment
@NathanOliver Уверен, что нет. Это не описывается как проблема с библиотекой, это описывается как новая функция библиотеки. Так что я думаю, что это ново для С++ 20. - person Barry; 01.02.2019
comment
Хм. Если это так, мне нужно спросить, могут ли они исправить страницу. - person NathanOliver; 01.02.2019
comment
@NathanOliver Или один из нас может это исправить :-) - person Barry; 01.02.2019
comment
@Барри, спасибо за отличный ответ! И за то, что я узнал о eel.is/c++draft - person Kilian; 01.02.2019
comment
Я ожидал (и до сих пор ожидаю), что этот документ будет реализован задним числом. - person T.C.; 02.02.2019

В каждой версии стандарта C++ есть ошибки. Сотни из них.

Реализации C++ стремятся быть полезными, поэтому они не придерживаются рабски опубликованного стандартного текста. Нет причин поддерживать совместимость «баг за багом» с листом бумаги.

(В качестве крайнего примера, до C++17 стандарт технически требовал, чтобы <int> в std::vector<int> v; анализировалось как имя-заголовка, а затем отклонялось, поскольку оно не находится внутри директивы #include. говоря, что ни один компилятор этого не сделает.)

Cppreference также стремится быть полезным. Таким образом, мы также не поддерживаем пошаговую совместимость со стандартами. Когда фрагмент текста впервые появляется в документе, опубликованном ISO, он бесполезен (за исключением, пожалуй, стандартных историков); как программистов, нас заботит то, что мы получаем, когда используем -std=c++17 или любой эквивалентный флаг вашей реализации. В результате наша документация предназначена для гипотетической полной и правильной реализации каждого стандарта C++, а также для всех последующих исправлений и разъяснений, применимых к этому стандарту.* Мы используем текущие реализации в качестве доказательства того, что такая гипотетическая реализация сделал бы.

Когда для определенного изменения нет текущей реализации, мы оцениваем характер изменения, чтобы предсказать, как реализации справятся с ним. Изменения основного языка, которые должны иметь обратную силу, помечаются как отчеты о дефектах, что упрощает вызов (хотя иногда они не доходят до конца, и это не указано в маркировке). Однако изменения в библиотеке не сопровождаются постоянно применяемыми метками «DR», поэтому выбор в большей степени зависит от нас.

В данном конкретном случае, хотя P0608 не помечен как отчет о дефекте, он исправляет крайне сомнительное поведение в C++17 вскоре после его публикации. Кроме того, крайне нежелательно, чтобы код, подобный std::variant<std::string, bool> x = "abcd";, незаметно менял значение в одной и той же реализации в зависимости от стандартного режима. Код, основанный на std::variant, также редко встречается в дикой природе (частично поэтому комитет даже одобрил «критическое» изменение в первую очередь). В результате я предсказал, что документ в конечном итоге будет применяться задним числом, и соответствующим образом задокументировал его.


*Это изменение философии, произошедшее несколько лет назад; в результате у нас все еще есть много случаев, когда исправление не рассматривается в документации как имеющее обратную силу, хотя должно быть таковым. Со временем они постепенно очищаются.

person T.C.    schedule 02.02.2019