Mengapa `decltype (static_cast <T> (...))` tidak selalu `T`?

24

Untuk kode berikut, semua kecuali pernyataan terakhir berlalu:

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
}

Mengapa pernyataan terakhir ini gagal, dan static_cast<T>tidak selalu mengembalikan a T?

Eric
sumber
Saya menambahkan T_cast i{1};saya dapatkan invalid initialization of non-const reference of type 'T_cast' {aka 'int (&)(int)'} from an rvalue of type '<brace-enclosed initializer list>', jadi untuk alasan apa pun T_castadalah int (&)(int)bukan int (&&)(int).
Kevin

Jawaban:

21

Ini sulit dikodekan dalam definisi static_cast:

[expr.static.cast] (penekanan pada saya)

1 Hasil dari ekspresi static_­cast<T>(v)adalah hasil dari mengubah ekspresi vmenjadi tipe T. Jika Tmerupakan tipe referensi nilai atau referensi nilai untuk tipe fungsi, hasilnya adalah nilai ; jika Treferensi nilai untuk jenis objek, hasilnya adalah nilai x; jika tidak, hasilnya adalah nilai awal. The static_­cast Operator tidak akan dibuang constness.

decltype menghormati kategori nilai operannya, dan menghasilkan referensi nilai lv untuk ekspresi nilai l.

Alasannya mungkin karena nama fungsi itu sendiri selalu menjadi nilai, dan nilai dari jenis fungsi tidak dapat muncul "di alam liar". Karena itu, casting ke tipe itu mungkin tidak masuk akal.

StoryTeller - Unslander Monica
sumber
pertanyaan ini membahas secara lebih terperinci "nilai [dari] tipe fungsi [tidak] muncul [di]" di alam liar ""
Eric