Por que `decltype (static_cast <T> (...))` nem sempre é `T`?

24

Para o código a seguir, quase a última asserção passa:

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 que esta última afirmação falha e static_cast<T>nem sempre retorna uma T?

Eric
fonte
Acrescento T_cast i{1};que recebo invalid initialization of non-const reference of type 'T_cast' {aka 'int (&)(int)'} from an rvalue of type '<brace-enclosed initializer list>', portanto, por qualquer motivo, T_casté um int (&)(int)e não um int (&&)(int).
Kevin

Respostas:

21

Isso é codificado na definição de static_cast:

[expr.static.cast] (grifo meu)

1 O resultado da expressão static_­cast<T>(v)é o resultado da conversão da expressão vem tipo T. Se Tfor um tipo de referência lvalue ou uma referência rvalue ao tipo de função, o resultado será um lvalue ; se Té uma referência rvalue ao tipo de objeto, o resultado é um xvalue; caso contrário, o resultado é um pré-valor. O static_­cast operador não deve rejeitar a constância.

decltype respeita a categoria de valor de seu operando e produz uma referência lvalue para expressões lvalue.

O raciocínio pode ser devido aos nomes de funções sempre serem lvalues ​​e, portanto, um rvalue de um tipo de função não pode aparecer "em estado selvagem". Como tal, transmitir para esse tipo provavelmente faz pouco sentido.

Contador de Histórias - Monica Sem Calúnia
fonte
esta pergunta aborda mais detalhadamente "os valores de um tipo de função [não] aparecem [ing]" em estado selvagem ""
Eric