C++11 result_of menyimpulkan tipe fungsi saya gagal

Saya sedang mencoba program di bawah ini:

#include<type_traits>
using namespace std;
template <class F, class R = typename result_of<F()>::type>
R call(F& f) { return f(); }
int answer() { return 42; }

int main()
{
    call(answer); 
    return 0;
}

"panggilan (jawaban)" gagal dikompilasi

VC mengatakan 'R call(F&)' tidak dapat menyimpulkan argumen templat untuk 'R'

GCC mengatakan |catatan: pengurangan/substitusi argumen templat gagal:|kesalahan: fungsi mengembalikan suatu fungsi

Saya tidak yakin apakah "nama fungsi" dapat digunakan untuk templat. Di mana kesalahan saya, bagaimana agar panggilan (jawaban) saya berfungsi?


person Troskyvs    schedule 29.06.2016    source sumber


Jawaban (3)


Anda dapat menggunakan referensi penerusan dalam kasus berikut:

#include<type_traits>
#include<utility>
#include<cassert>

using namespace std;

template <class F, class R = typename result_of<F()>::type>
R call(F&& f) { return std::forward<F>(f)(); }

int answer() { return 42; }

int main()
{
    assert(call(answer) == 42);
    return 0;
}

Biasanya menghindari masalah.

Meskipun demikian, mengapa kode Anda tidak berfungsi dijelaskan dengan baik oleh @T.C. dalam jawabannya.
Lihat juga komentar untuk pertanyaan ini untuk rincian lebih lanjut.

person skypjack    schedule 29.06.2016
comment
Tetapi mengapa saya tidak bisa menyebut f sebagai nilai? nama fungsi selalu bukan nilai? - person Troskyvs; 29.06.2016
comment
Anda dapat menyebutnya sebagai nilai. Dalam contoh Anda, karena cara kerja pengurangan tipe templat, F adalah tipe fungsi, bukan referensinya. Menggunakan referensi penerusan, F dideduksi sebagai referensi ke answer. Coba tambahkan static_assert(std::is_reference<F>::value, "!"); dalam call dalam contoh saya dan dalam contoh @T.C. - person skypjack; 29.06.2016
comment
Tes lain akan menambahkan std::function<F> func; dalam call pada kedua contoh. Ini akan membantu Anda memahami apa yang terjadi di sana dengan pengurangan tipe untuk F. - person skypjack; 29.06.2016

Anda memanggil f sebagai nilai, jadi:

template <class F, class R = typename result_of<F&()>::type>
//                                               ^
R call(F& f) { return f(); }
person T.C.    schedule 29.06.2016
comment
Saya kurang paham dengan result_of‹F&()›::type ini. Apa yang dimaksud dengan F&() di sini? - person Troskyvs; 29.06.2016

Saya kira Anda dapat menghindari argumen templat kedua dan menggunakan kombinasi auto dan decltype().

Sesuatu seperti

#include<type_traits>

using namespace std;

template <class F>
auto call(F& f) -> decltype( f() )
 { return f(); } 

int answer()
 { return 42; }

int main()
{
    call(answer); 

    return 0;
}

Jika Anda (ketika Anda) dapat menggunakan C++14, Anda cukup menggunakan auto

template <class F>
auto call(F& f)
 { return f(); } 

p.s.: maaf atas bahasa Inggris saya yang buruk.

person max66    schedule 29.06.2016
comment
Kedua versi ini melakukan hal yang berbeda. - person T.C.; 29.06.2016
comment
Mengapa dua versi melakukan hal yang berbeda? - person Troskyvs; 29.06.2016
comment
@T.C. - maksud Anda auto dapat kehilangan konstanta dan referensi di mana decltype(f()) menyimpannya? Jadi seharusnya decltype(auto) bukannya auto di C++14? - person max66; 29.06.2016