Hãy xem xét chương trình sau đây.
#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 );
}
Chương trình biên dịch thành công và đầu ra của nó là
g( 42 );
Bây giờ hãy đổi tên hàm phi mẫu gthành 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 );
}
Bây giờ chương trình không được biên dịch bởi gcc HEAD 10.0.0 20200 và clang HEAD 10.0.0 nhưng được biên dịch thành công bởi Visual C ++ 2019 ..
Ví dụ, trình biên dịch gcc phát hành tập hợp các thông báo sau.
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 )
| ~~~~^
Vì vậy, một câu hỏi được đặt ra: mã có nên được biên dịch không và lý do nào khiến mã không được biên dịch bởi gcc và clang?
g(thay vì &g) cho mẫu hàm gây ra sự phân rã kiểu (một tham chiếu giá trị hàm phân rã thành một con trỏ tới hàm: void(&)(T)=> void(*)(T)). Sự hội tụ ngầm này xảy ra bởi vì không có sự fquá tải nào khác với một kết hợp tốt hơn. Trong ví dụ thứ hai, có một sự mơ hồ mà fbạn thực sự muốn gọi bởi vì ... nó cũng không biết đó flà đối số nào.