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 g
thà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ự f
quá 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à f
bạn thực sự muốn gọi bởi vì ... nó cũng không biết đó f
là đối số nào.