Jika Anda membutuhkan jenis sesuatu yang bukan sesuatu seperti panggilan fungsi, std::result_of
itu tidak berlaku. decltype()
dapat memberi Anda jenis ekspresi apa pun.
Jika kita membatasi diri hanya pada cara yang berbeda untuk menentukan jenis kembalian dari sebuah panggilan fungsi (antara std::result_of_t<F(Args...)>
dan decltype(std::declval<F>()(std::declval<Args>()...)
), maka ada perbedaan.
std::result_of<F(Args...)
didefinisikan sebagai:
Jika ekspresi
INVOKE (declval<Fn>(), declval<ArgTypes>()...)
terbentuk dengan baik saat diperlakukan sebagai operan yang tidak dievaluasi (Klausul 5), tipe anggota typedef harus menamai tipe decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
jika tidak, tidak boleh ada tipe anggota.
Perbedaan antara result_of<F(Args..)>::type
dan decltype(std::declval<F>()(std::declval<Args>()...)
adalah tentang itu INVOKE
. Menggunakan declval
/ decltype
secara langsung, selain sedikit lebih lama untuk mengetik, hanya valid jika F
dapat dipanggil secara langsung (tipe objek fungsi atau fungsi atau penunjuk fungsi). result_of
Selain itu mendukung petunjuk ke fungsi anggota dan petunjuk ke data anggota.
Awalnya, menggunakan declval
/ decltype
menjamin ekspresi ramah SFINAE, sedangkan std::result_of
bisa memberi Anda kesalahan keras alih-alih kegagalan deduksi. Itu telah diperbaiki di C ++ 14: std::result_of
sekarang harus ramah SFINAE (terima kasih untuk makalah ini ).
Jadi pada kompiler C ++ 14 yang sesuai, std::result_of_t<F(Args...)>
sangat unggul. Ini jelas, lebih pendek, dan benar † mendukung lebih F
s ‡ .
† Kecuali, jika Anda menggunakannya dalam konteks di mana Anda tidak ingin mengizinkan petunjuk untuk anggota, jadi
std::result_of_t
akan berhasil dalam kasus di mana Anda mungkin ingin gagal.
‡ Dengan pengecualian. Meskipun mendukung pointer ke anggota, result_of
tidak akan berfungsi jika Anda mencoba membuat id jenis yang tidak valid . Ini akan mencakup fungsi yang mengembalikan fungsi atau mengambil tipe abstrak berdasarkan nilai. Ex.:
template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }
int answer() { return 42; }
call(answer); // nope
Penggunaan yang benar akan dilakukan result_of_t<F&()>
, tetapi itu adalah detail yang tidak perlu Anda ingat decltype
.
decltype
lebih buruk tetapi juga lebih kuat.result_of
hanya dapat digunakan untuk tipe yang dapat dipanggil dan membutuhkan tipe sebagai argumen. Misalnya, Anda tidak dapat menggunakan diresult_of
sini:template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );
jika argumen dapat berupa tipe aritmatika (tidak ada fungsiF
yang dapat Anda definisikanF(T,U)
untuk mewakilit+u
. Untuk tipe yang ditentukan pengguna, Anda bisa. Dengan cara yang sama (saya belum benar-benar bermain dengannya) saya bayangkan bahwa panggilan ke metode anggota mungkin sulit dilakukanresult_of
tanpa menggunakan pengikat atau lambda