当涉及重载函数作为参数时,模板参数推导如何工作?
How does template argument deduction work when an overloaded function is involved as an argument?
这是
中提到的更复杂的问题
下面的代码 compiles without any problem:
void foo() {}
void foo(int) {}
void foo(double) {}
void foo(int, double) {}
// Uncommenting below line break compilation
//template<class T> void foo(T) {}
template<class X, class Y> void bar(void (*f)(X, Y))
{
f(X(), Y());
}
int main()
{
bar(foo);
}
模板参数推导似乎不是一项具有挑战性的任务 - 只有一个函数 foo()
接受两个参数。但是,取消注释 foo()
的模板重载(它仍然只有一个参数)会无缘无故地中断编译。 gcc 5.x/6.x 和 clang 3.9.
编译均失败
是否可以通过重载resolution/template参数推导的规则来解释,或者它应该被定义为那些编译器的缺陷?
如您的链接问题的答案所述:
[temp.deduct.call]/6:
When P
is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated
as a non-deduced context.
由于重载集包含函数模板,参数被视为非推导上下文。这会导致模板参数推导失败:
[temp.deduct.type]/4:
[...]If a template parameter is used only in non-deduced
contexts and is not explicitly specified, template argument deduction fails.
这个失败的推论给了你你的错误。请注意,如果您显式指定参数,代码将成功编译:
bar<int,double>(foo);
这是
下面的代码 compiles without any problem:
void foo() {}
void foo(int) {}
void foo(double) {}
void foo(int, double) {}
// Uncommenting below line break compilation
//template<class T> void foo(T) {}
template<class X, class Y> void bar(void (*f)(X, Y))
{
f(X(), Y());
}
int main()
{
bar(foo);
}
模板参数推导似乎不是一项具有挑战性的任务 - 只有一个函数 foo()
接受两个参数。但是,取消注释 foo()
的模板重载(它仍然只有一个参数)会无缘无故地中断编译。 gcc 5.x/6.x 和 clang 3.9.
是否可以通过重载resolution/template参数推导的规则来解释,或者它应该被定义为那些编译器的缺陷?
如您的链接问题的答案所述:
[temp.deduct.call]/6:
WhenP
is a function type, pointer to function type, or pointer to member function type:— If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.
由于重载集包含函数模板,参数被视为非推导上下文。这会导致模板参数推导失败:
[temp.deduct.type]/4:
[...]If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
这个失败的推论给了你你的错误。请注意,如果您显式指定参数,代码将成功编译:
bar<int,double>(foo);