Применяется ли временное преобразование материализации к операнду const_cast

int main(){
  const_cast<int&&>(0);
}

Согласно expr.const.cast № 4

Для двух типов объектов T1 и T2, если указатель на T1 может быть явно преобразован в тип «указатель на T2» с помощью const_cast, тогда также могут быть выполнены следующие преобразования:

  • lvalue типа T1 может быть явно преобразовано в lvalue типа T2, используя приведение const_cast ‹T2 &›;
  • glvalue типа T1 может быть явно преобразован в xvalue типа T2, используя приведение const_cast ‹T2 &&›; а также
  • если T1 является типом класса, prvalue типа T1 может быть явно преобразовано в xvalue типа T2, используя приведение const_cast ‹T2 &&›.

Результат ссылки const_cast относится к исходному объекту, если операнд является значением glvalue, и к результату применения преобразования временной материализации в противном случае.

Поскольку операнд 0 - это prvalue типа int, а указанный тип - это ссылка rvalue типа int. Следовательно, второй пункт может быть применен здесь после выполнения временного преобразования материализации, при котором операндом источника будет значение gl согласно expr # basic.lval-7

Каждый раз, когда prvalue появляется как операнд оператора, который ожидает glvalue для этого операнда, применяется временное преобразование материализации для преобразования выражения в xvalue.

Однако этот фрагмент отклонен как Clang, так и GCC. Если мы изменим операнд на int{0}

int main(){
  const_cast<int&&>(int{0});
}

Код принимает только GCC. Но следующий код по-прежнему не может быть скомпилирован GCC.

int main(){
  const_cast<int&&>(int(0));
}

Я не знаю, в чем разница, когда операндом является 0, int{0} и int(0) соответственно. На мой взгляд, все они prvalue типа int.

typedef int *A[3];  
typedef const int *const CA[3];
int main(){
   A &&r2 = const_cast<A&&>(CA{}); 
}

Этот код является формальным примером expr.const.cast # 3. К сожалению, он отклонен Clang.

Не знаю, можно ли это рассматривать как дефект стандарта или некорректную реализацию Clang? Я не знаю, какова цель третьего маркера [expr.const.cast # 4], почему в нем специально упоминается prvalue типа класса? (Намерено ли оно сказать, что будет применяться только prvalue типа класса временная материализация к нему? Однако это явно противоречит примеру для prvalue типа массива).


person xmh0511    schedule 01.03.2021    source источник
comment
CWG1965?   -  person Language Lawyer    schedule 01.03.2021
comment
@LanguageLawyer Мне кажется, что всякий раз, когда glvalue ожидается как операнд оператора, общее правило expr # basic.lval-7 должен привести исходный операнд (prvalue) к glvalue, за исключением того, что правило явно запрещает это преобразование (временное преобразование материализации). В противном случае [expr # basic.lval-7] будет немного противоречивым.   -  person xmh0511    schedule 02.03.2021


Ответы (1)


Ключевым моментом здесь является если T1 - это тип класса. Тип int не является типом класса, поэтому 4.3 не применяется. Если бы вы использовали std::string, это сработало бы:

const std::string && x = const_cast<std::string&&>(std::string("foo") + "bar");
person Serge Ballesta    schedule 01.03.2021
comment
Итак, как вы интерпретируете формальный пример в приведенной ниже части expr.const.cast # 3? Массив не является типом класса. - person xmh0511; 01.03.2021