Pour le code suivant, toutes les assertions sauf la dernière passent:
template<typename T>
constexpr void assert_static_cast_identity() {
using T_cast = decltype(static_cast<T>(std::declval<T>()));
static_assert(std::is_same_v<T_cast, T>);
}
int main() {
assert_static_cast_identity<int>();
assert_static_cast_identity<int&>();
assert_static_cast_identity<int&&>();
// assert_static_cast_identity<int(int)>(); // illegal cast
assert_static_cast_identity<int (&)(int)>();
assert_static_cast_identity<int (&&)(int)>(); // static assert fails
}
Pourquoi cette dernière assertion échoue, et static_cast<T>
ne renvoyant pas toujours un T
?
Ceci est codé en dur dans la définition de static_cast
:
[expr.static.cast] (c'est moi qui souligne)
1 Le résultat de l'expression
static_cast<T>(v)
est le résultat de la conversion de l'expressionv
en typeT
. SiT
est un type de référence lvalue ou une référence rvalue au type de fonction, le résultat est une lvalue ; siT
est une référence rvalue au type d'objet, le résultat est une xvalue; sinon, le résultat est une valeur. L'opérateurstatic_cast
Ne doit pas annuler la constance.
decltype
respecte la catégorie de valeur de son opérande et produit une référence lvalue pour les expressions lvalue.
Le raisonnement peut être dû au fait que les noms de fonctions eux-mêmes sont toujours des valeurs l, et donc une valeur r d'un type de fonction ne peut pas apparaître "dans la nature". En tant que tel, le casting sur ce type n'a probablement aucun sens.