다음 프로그램을 고려하십시오.
#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 및 clang이 코드를 컴파일하지 않는 이유는 무엇입니까?
Godbolt에서 자신을 참조하십시오
—
Zereges
참고 : 첫 번째 예제에서
—
Xeverous
g
(대신 &g
)를 함수 템플릿에 전달하면 형식이 소멸됩니다 (함수 lvalue 참조는 함수에 대한 포인터로 소멸됩니다 : void(&)(T)
=> void(*)(T)
). 이 암시 적 변환 f
은 더 일치하는 다른 과부하 가 없기 때문에 발생합니다 . 두 번째 예에는 f
실제로 호출하려는 모호성이 있습니다. 왜냐하면 f
어느 쪽이 인수 인지 알 수 없기 때문 입니다.