函数类型参数的模板参数推导
Template argument deduction for an argument of a function type
考虑以下程序。
#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不编译的原因是什么?
在我看来,gcc 和 clang 是正确的。这不应该编译。当提供的参数是包含函数模板 [temp.deduct.type]/5.5:
的重载集时,您希望从中推导 T
的函数参数在此处变为非推导上下文
The non-deduced contexts are:
- […]
A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions ([over.over]), and one or more of the following apply:
- […]
- the set of functions supplied as an argument contains one or more function templates.
- […]
因此,无法推导出T
,并且由于没有转换,另一个重载不可行;正是 gcc 所说的......
这是两个重载函数,应该选择非模板函数比较
到模板化函数,因此选择了 f(int x) 因此将函数作为参数传递
在必须传递 int 的函数中是不可能的。
以下应该有效。谢谢
void f( void ( *fn )( int ) ){
fn( 42 );
}
void f( int x ){
std::cout << "f( " << x << " );\n";
}
int main(){
f( f );
}
考虑以下程序。
#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不编译的原因是什么?
在我看来,gcc 和 clang 是正确的。这不应该编译。当提供的参数是包含函数模板 [temp.deduct.type]/5.5:
的重载集时,您希望从中推导T
的函数参数在此处变为非推导上下文
The non-deduced contexts are:
- […]
A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions ([over.over]), and one or more of the following apply:
- […]
- the set of functions supplied as an argument contains one or more function templates.
- […]
因此,无法推导出T
,并且由于没有转换,另一个重载不可行;正是 gcc 所说的......
这是两个重载函数,应该选择非模板函数比较 到模板化函数,因此选择了 f(int x) 因此将函数作为参数传递 在必须传递 int 的函数中是不可能的。 以下应该有效。谢谢
void f( void ( *fn )( int ) ){
fn( 42 );
}
void f( int x ){
std::cout << "f( " << x << " );\n";
}
int main(){
f( f );
}