พิจารณาโปรแกรมต่อไปนี้
#include <iostream>
template <typename T>
void f( void ( *fn )( T ) )
{
fn( 42 );
}
void g( int x )
{
std::cout << "g( " << x << " );\n";
}
int main()
{
f( g );
}
โปรแกรมคอมไพล์ได้สำเร็จและผลลัพธ์คือ
g( 42 );
ตอนนี้ขอเปลี่ยนชื่อฟังก์ชั่นที่ไม่ใช่แม่แบบเพื่อg
f
#include <iostream>
template <typename T>
void f( void ( *fn )( T ) )
{
fn( 42 );
}
void f( int x )
{
std::cout << "f( " << x << " );\n";
}
int main()
{
f( f );
}
ตอนนี้โปรแกรมไม่ได้ถูกคอมไพล์ด้วย gcc HEAD 10.0.0 20200 และ clang HEAD 10.0.0 แต่เรียบเรียงโดย Visual C ++ 2019 เรียบร้อยแล้ว
ตัวอย่างเช่นคอมไพเลอร์ gcc ออกชุดข้อความต่อไปนี้
prog.cc: In function 'int main()':
prog.cc:22:10: error: no matching function for call to 'f(<unresolved overloaded function type>)'
22 | f( f );
| ^
prog.cc:4:6: note: candidate: 'template<class T> void f(void (*)(T))'
4 | void f( void ( *fn )( T ) )
| ^
prog.cc:4:6: note: template argument deduction/substitution failed:
prog.cc:22:10: note: couldn't deduce template parameter 'T'
22 | f( f );
| ^
prog.cc:14:6: note: candidate: 'void f(int)'
14 | void f( int x )
| ^
prog.cc:14:13: note: no known conversion for argument 1 from '<unresolved overloaded function type>' to 'int'
14 | void f( int x )
| ~~~~^
ดังนั้นจึงมีคำถามเกิดขึ้น: ควรรวบรวมรหัสและเหตุผลที่รหัสไม่รวบรวมโดย gcc และเสียงดังกราวคืออะไร?
g
(แทน&g
) ไปยังเทมเพลตฟังก์ชันทำให้เกิดการสลายประเภท (การอ้างอิงฟังก์ชัน lvalue จะสลายตัวไปยังตัวชี้ไปยังฟังก์ชัน: void(&)(T)
=> void(*)(T)
) การแปลงโดยนัยนี้เกิดขึ้นเนื่องจากไม่มีf
โอเวอร์โหลดอื่นที่มีการจับคู่ที่ดีกว่า ในตัวอย่างที่สองมีความกำกวมที่f
คุณต้องการโทรจริงเพราะ ... ไม่รู้ว่าสิ่งใดf
เป็นอาร์กิวเมนต์เช่นกัน