Есть такой код:
#include <iostream>
void test(const int& val)
{
const_cast<int&>(val) = 42;
}
int main()
{
int val1 = 0, val2 = 0, val3 = 0;
test(val1);
test(val2 + 0);
test(static_cast<int>(val3)); //Интересная строка;
std::cout << val1 << " " << val2 << " " << val3 << std::endl;
return 0;
}
Вывод GCC:
42 0 0
Вывод MS Visual Studio:
42 0 42
Кто прав и почему?
static_cast<int>(val3), согласно [expr.static.cast]p1, является rvalue-выражением.
Согласно [dcl.init.ref]p5.3, инициализация константной ссылки rvalue-выражением проводит материализацию prvalue, создавая константный временный объект и привязывая ссылку к нему.
[dcl.type.cv]p4 явно запрещает нам модифицировать константные объекты.
Исходя из всех этих пунктов, правильный ответ будет 42 0 0, но т.к. во втором и третьем случае мы имеем неопределённое поведение, то и вывод может быть любым. В результате, разговор о правильном ответе, в целом, не имеет смысла.
Тем не менее студия выводит 42 0 42 не из-за UB, а потому что без флага /permissive- срабатывает её расширение, которое игнорирует static_cast, когда тип не меняется. В результате в третьем случае передается lvalue, а не rvalue. Но это поведение противоречит стандарту и является расширением MSVC, которое, я полагаю, существует для некоторой обратной совместимости.
Продвижение своими сайтами как стратегия роста и независимости