¿Por qué `decltype (static_cast <T> (...))` no siempre es `T`?

24

Para el siguiente código, todos, excepto la última aserción, pasan:

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
}

¿Por qué esta última afirmación falla y static_cast<T>no siempre devuelve un T?

Eric
fuente
Agrego T_cast i{1};que obtengo invalid initialization of non-const reference of type 'T_cast' {aka 'int (&)(int)'} from an rvalue of type '<brace-enclosed initializer list>', así que por cualquier razón T_castes un en int (&)(int)lugar de un int (&&)(int).
Kevin

Respuestas:

21

Esto está codificado en la definición de static_cast:

[expr.static.cast] (énfasis mío)

1 El resultado de la expresión static_­cast<T>(v)es el resultado de convertir la expresión va tipo T. Si Tes un tipo de referencia lvalue o una referencia rvalue al tipo de función, el resultado es un lvalue ; si Tes una referencia de rvalue al tipo de objeto, el resultado es un xvalue; de lo contrario, el resultado es un prvalue. El static_­cast operador no debe desechar la constidad.

decltype respeta la categoría de valor de su operando y produce una referencia de valor para las expresiones de valor.

El razonamiento puede deberse a que los nombres de las funciones siempre son valores, por lo que un valor de un tipo de función no puede aparecer "en la naturaleza". Como tal, lanzar a ese tipo probablemente tenga poco sentido.

StoryTeller - Unslander Monica
fuente
esta pregunta aborda con más detalle "rvalue [s] de un tipo de función [no] aparece [ing]" en la naturaleza ""
Eric