Saya mengalami kesulitan memahami kebutuhan std::result_of
dalam C ++ 0x. Jika saya mengerti dengan benar, result_of
digunakan untuk mendapatkan jenis yang dihasilkan dari pemanggilan objek fungsi dengan jenis parameter tertentu. Sebagai contoh:
template <typename F, typename Arg>
typename std::result_of<F(Arg)>::type
invoke(F f, Arg a)
{
return f(a);
}
Saya tidak terlalu melihat perbedaannya dengan kode berikut:
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(f(a)) //uses the f parameter
{
return f(a);
}
atau
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(F()(a)); //"constructs" an F
{
return f(a);
}
Satu-satunya masalah yang dapat saya lihat dengan dua solusi ini adalah kita perlu:
- memiliki contoh dari functor untuk menggunakannya dalam ekspresi yang diteruskan ke jenis deklarasi.
- tahu konstruktor yang ditentukan untuk functor.
Apakah saya benar dalam berpikir bahwa satu-satunya perbedaan antara decltype
dan result_of
apakah yang pertama membutuhkan ekspresi sedangkan yang kedua tidak?
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 lambdastd::declval
, seperti kode yang saya tunjukkan di atas. Tentu saja, ini jelek :)result_of
dan jenis helpernyaresult_of_t
tidak digunakan lagi mulai C ++ 17 mendukunginvoke_result
daninvoke_result_t
, mengurangi beberapa pembatasan yang sebelumnya. Ini tercantum di bagian bawah en.cppreference.com/w/cpp/types/result_of .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...)>
dandecltype(std::declval<F>()(std::declval<Args>()...)
), maka ada perbedaan.std::result_of<F(Args...)
didefinisikan sebagai:Perbedaan antara
result_of<F(Args..)>::type
dandecltype(std::declval<F>()(std::declval<Args>()...)
adalah tentang ituINVOKE
. Menggunakandeclval
/decltype
secara langsung, selain sedikit lebih lama untuk mengetik, hanya valid jikaF
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, sedangkanstd::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 lebihF
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.:Penggunaan yang benar akan dilakukan
result_of_t<F&()>
, tetapi itu adalah detail yang tidak perlu Anda ingatdecltype
.sumber
T
dan fungsitemplate<class F> result_of_t<F&&(T&&)> call(F&& f, T&& arg) { return std::forward<F>(f)(std::move(arg)); }
, apakah penggunaannyaresult_of_t
benar?f
adalah aconst T
, haruskah kita gunakanresult_of_t<F&&(const T&)>
?