ผลลัพธ์ C ++ 11 ของการอนุมานประเภทฟังก์ชันของฉันล้มเหลว

ฉันกำลังลองใช้โปรแกรมด้านล่าง:

#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;
}

"การโทร (รับสาย)" ล้มเหลวในการรวบรวม

VC บอกว่า 'การโทร R (F&)' ไม่สามารถสรุปอาร์กิวเมนต์เทมเพลตสำหรับ 'R'

GCC ระบุว่า |หมายเหตุ: การหักล้าง/การทดแทนอาร์กิวเมนต์เทมเพลตล้มเหลว:|ข้อผิดพลาด: ฟังก์ชันส่งคืนฟังก์ชัน

ฉันไม่แน่ใจว่า "ชื่อฟังก์ชัน" สามารถใช้กับเทมเพลตได้หรือไม่ ฉันผิดพลาดตรงไหน จะทำให้การโทร (รับสาย) ทำงานได้อย่างไร?


person Troskyvs    schedule 29.06.2016    source แหล่งที่มา


คำตอบ (3)


คุณสามารถใช้การอ้างอิงการส่งต่อในกรณีเหล่านี้:

#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;
}

มักจะหลีกเลี่ยงปัญหา

ที่กล่าวว่าเหตุใดรหัสของคุณจึงใช้งานไม่ได้ @T.C. อธิบายไว้อย่างดี ในคำตอบของเขา
ดูความคิดเห็นต่อคำถามนี้เพื่อดูรายละเอียดเพิ่มเติม

person skypjack    schedule 29.06.2016
comment
แต่ทำไมฉันไม่สามารถเรียก f เป็น lvalue ได้? ชื่อฟังก์ชันไม่ใช่ค่า lvalue เสมอไปใช่ไหม - person Troskyvs; 29.06.2016
comment
คุณสามารถเรียกมันว่าค่า lvalue ได้ ในตัวอย่างของคุณ เนื่องจากวิธีการทำงานของการหักประเภทเทมเพลต F จึงเป็นประเภทฟังก์ชัน ไม่ใช่การอ้างอิง เมื่อใช้การอ้างอิงการส่งต่อ F จะถูกอนุมานว่าเป็นการอ้างอิงถึง answer ลองเพิ่ม static_assert(std::is_reference<F>::value, "!"); ภายใน call ในตัวอย่างของฉันและใน @T.C. - person skypjack; 29.06.2016
comment
การทดสอบอื่นจะเพิ่ม std::function<F> func; ภายใน call ในทั้งสองตัวอย่าง สิ่งนี้จะช่วยให้คุณเข้าใจสิ่งที่เกิดขึ้นที่นั่นด้วยการหักประเภทสำหรับ F - person skypjack; 29.06.2016

คุณกำลังเรียก f เป็น lvalue ดังนั้น:

template <class F, class R = typename result_of<F&()>::type>
//                                               ^
R call(F& f) { return f(); }
person T.C.    schedule 29.06.2016
comment
ฉันไม่ค่อยเข้าใจ result_of‹F&()›::type นี้มากนัก F&() หมายถึงอะไรที่นี่? - person Troskyvs; 29.06.2016

ฉันคิดว่าคุณสามารถหลีกเลี่ยงอาร์กิวเมนต์เทมเพลตที่สองได้และใช้การรวมกันของ auto และ decltype()

สิ่งที่ต้องการ

#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;
}

หากคุณ (เมื่อคุณ) สามารถใช้ C++14 ได้ คุณสามารถใช้เพียง auto

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

ป.ล. : ขอโทษสำหรับภาษาอังกฤษที่ไม่ดีของฉัน

person max66    schedule 29.06.2016
comment
สองเวอร์ชันนี้ทำสิ่งที่แตกต่างกัน - person T.C.; 29.06.2016
comment
ทำไมสองเวอร์ชันถึงทำสิ่งที่แตกต่างกัน? - person Troskyvs; 29.06.2016
comment
@ที.ซี. - คุณหมายถึงว่า auto สามารถสูญเสีย consts และการอ้างอิงโดยที่ decltype(f()) รักษาไว้ได้หรือไม่ นั่นควรเป็น decltype(auto) แทนที่จะเป็น auto ใน C ++ 14? - person max66; 29.06.2016