Константное приведение к не-указательному не ссылочному типу

Из [expr.const.cast] / 3:

Для двух похожих типов T1 и T2 prvalue типа T1 может быть явно преобразовано в тип T2 с помощью const_cast, если, учитывая cv-разложения обоих типов, каждое P i 1 совпадает с P i 2 для всех i. Результат const_cast относится к исходной сущности.

Кажется, что константное приведение к не-указательному не ссылочному типу разрешено. Например, следующая функция

void f(int a)
{
    const_cast<int>(a);
}

должны быть правильно сформированы, поскольку int и int, безусловно, являются схожими типами и не имеют P i в их cv-разложениях (отсюда утверждение, что "каждый P i 1 совпадает с P i 2 для всех i "должно быть истинным).

Однако и GCC, и Clang отклоняют приведенный выше код (см. Compiler Explorer). Сообщения об ошибках

Лязг:

<source>: In function 'void f(int)':
<source>:3:22: error: invalid use of const_cast with type 'int', which is not a pointer, reference, nor a pointer-to-data-member type
    3 |     const_cast<int>(a);
      |                      ^

GCC:

<source>: In function 'void f(int)':
<source>:3:5: error: invalid use of 'const_cast' with type 'int', which is not a pointer, reference, nor a pointer-to-data-member type
    3 |     const_cast<int>(a);
      |     ^~~~~~~~~~~~~~~~~~

Я что-то упускаю или это ошибка компилятора?

ОБНОВЛЕНИЕ: тоже не работает:

void f()
{
    const_cast<int>(int{});
}

person xskxzr    schedule 03.04.2020    source источник
comment
Параметр a не является prvalue, это lvalue, поэтому приведение не выполняется.   -  person Remy Lebeau    schedule 03.04.2020
comment
@RemyLebeau Спасибо, пожалуйста, посмотрите мой отредактированный вопрос   -  person xskxzr    schedule 03.04.2020
comment
@RemyLebeau lvalue может быть неявно преобразовано в prvalue   -  person M.M    schedule 03.04.2020
comment
Я смотрел на это вчера, когда кто-то спросил, где может происходить преобразование lvalue для типов классов; если типы, не являющиеся указателями, похожи, тогда T t; const_cast<T>(t) будет примером (который материализует временный)   -  person M.M    schedule 03.04.2020


Ответы (1)


В C ++ 17 типы не похожи, поэтому цитируемый текст неприменим. И поэтому это const_cast не разрешено, потому что const_cast не разрешено, если явно не разрешено.

C ++ 17 [conv.qual] / 1:

cv-декомпозиция типа T - это последовательность cv i и P i такой, что T

«Cv 0 P 0 cv 1 P 1 ··· cv n-1 P n-1 cv n Uдля n> 0,

где каждый cv i - это набор cv-квалификаторов (6.9.3), а каждый P i - это «указатель на» (11.3.1), «указатель на член класса C i типа »(11.3.3),« массив из N i »или« массив неизвестной границы »(11.3.4). [...]

а потом

Два типа T 1 и T 2 похожи, если у них есть cv-разложения с одинаковыми n такими, что соответствующие P i одинаковы, и типы, обозначенные U, одинаковы.

Требование n> 0 означает, что должно быть cv 0 P 0, то есть хотя бы один указатель в типе.


Последний черновик C ++ 20 изменяет n> 0 на n ≥ 0 в результате Проблема 2051. Но не вносит изменений в спецификацию const_cast. Я не могу сказать, намеренно это или недосмотр.

Так что, возможно, C ++ 20 сделает ваши const_cast выражения четко определенными, и компиляторам придется наверстать упущенное.

person M.M    schedule 03.04.2020
comment
Интересно, что текущий черновик допускает n = 0. Похоже, это касается основного языкового вопроса. - person xskxzr; 03.04.2020