为什么F
无法推断proxy()
?
应该可以,因为我限制它 - 仅适用于返回int
的函数。
#include <utility>
#include <iostream>
#include <type_traits>
using namespace std;
int foo(int bar) {
cout << "int" << endl;
return 2;
}
float foo(float bar) {
cout << "float" << endl;
return 1;
}
template <typename F, typename... Args>
typename enable_if<
is_same<
typename result_of<F(Args...)>::type,
int
>::value,
typename result_of<F(Args...)>::type
>::type
proxy(F func, Args&&... args) {
return func(forward<Args>(args)...);
}
int main() {
proxy(foo, 5);
}
这是错误:
b.cpp:29:17: error: no matching function for call to 'proxy(<unresolved overloaded function type>, int)'
b.cpp:24:1: note: template argument deduction/substitution failed:
b.cpp:29:17: note: couldn't deduce template parameter 'F'
答案 0 :(得分:4)
问题在于:
proxy(foo, 5);
编译器尝试推导出foo
的类型,但有2个重载。当然,它可以从Args...
中推导5
,但foo
的类型仍然是不可推导的,因为编译器在进行类型推导时不知道要选择哪个重载。
请注意,编译器需要知道函数签名中F
的类型,即此处,因此SFINAE会发挥其魔力:
is_same<
typename result_of<F(Args...)>::type,
int
>::value,
绝对没有办法从F
调用中正确推断proxy(foo, 5)
的类型,因此SFINAE无法启动。作为旁注,请注意C ++不能基于返回重载仅限类型。因此,您将无法仅根据返回类型区分具有相同名称的两个函数。你需要以某种方式强制参数匹配,这将使SFINAE超出非候选重载。
以某种方式相关:Deducing the return type of a standalone function
标准的相关引用,强调我的(感谢@ T.C。指出):
14.8.2.1从函数调用中减去模板参数[temp.deduct.call] /(6.2)
(6)当P是函数类型时,指向函数类型的指针或指向成员函数的指针类型:
(6.1)如果参数是包含一个或多个函数模板的重载集,则该参数将被视为非推导的上下文。
(6.2)如果参数是重载集(不包含函数) 模板),尝试使用每个的试验推论 成员。如果扣除成功只有一个过载 设置成员,该成员用作参数值 扣除。 如果多个成员的扣除成功 过载设置参数被视为非推导上下文。
答案 1 :(得分:2)
在您的示例中,foo
命名一组重载函数,模板参数推导无法选择一个重载而不是另一个重载,因为它们都是相同等级的匹配。
您的SFINAE约束检查在推断F
之后才会启动,因此从重载决策集中删除float foo(float)
没有任何帮助。
假设您将函数重命名为float
并返回foof
,那么您的示例将进行编译。但是,如果您尝试使用proxy
作为函数参数调用foof
,则代码将再次无法编译,这次是因为enable_if
约束。
要让您的示例以当前状态进行编译,您必须消除您传递给foo
的{{1}}
proxy