问题描述
int main(){
const_cast<int&&>(0);
}
对于两个对象类型 T1 和 T2,如果可以使用 const_cast 将指向 T1 的指针显式转换为“指向 T2 的指针”类型,则还可以进行以下转换:
- 可以使用强制转换 const_cast
; 将 T1 类型的左值显式转换为 T2 类型的左值; - 可以使用强制转换 const_cast
将 T1 类型的泛左值显式转换为 T2 类型的 xvalue;和 - 如果 T1 是类类型,则可以使用强制转换 const_cast
将 T1 类型的纯右值显式转换为 T2 类型的 xvalue。
如果操作数是泛左值,则引用 const_cast 的结果引用原始对象,否则引用应用临时物化转换的结果。
由于操作数 0
是 int 类型的纯右值,并且指定的类型是 int 类型的右值引用。因此,根据 expr#basic.lval-7
每当纯右值作为期望该操作数的泛左值的运算符的操作数出现时,就会应用临时物化转换以将表达式转换为 xvalue。
然而,这个 snippet 被 Clang 和 GCC 都拒绝了。如果我们将操作数更改为 int{0}
int main(){
const_cast<int&&>(int{0});
}
编译
int main(){
const_cast<int&&>(int(0));
}
当操作数分别为 0
、int{0}
和 int(0)
时,我不知道这里有什么区别。在我看来,它们都是 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]第三个子弹的用意是什么,为什么特别提到类类型的纯右值?(是说只应用类类型的纯右值吗?临时物化它吗?但是,它显然与数组类型的纯右值的例子相矛盾)。
解决方法
这里的关键是如果 T1 是一个类类型。类型 int
不是类类型,因此 4.3 不适用。如果您使用 std::string
,它会起作用:
const std::string && x = const_cast<std::string&&>(std::string("foo") + "bar");