2015-06-03 146 views
6

为什么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

由于有功能的两个重载...编译器不能推断上的基本价值未来(下一个)函数的参数...'代理(static_cast (foo),5);'会在这里做的伎俩 –

回答

4

问题是这样的:

proxy(foo, 5); 

编译器试图推断的foo类型,但有2点过载。当然,它可以从5推导出Args...,但foo的类型仍然是不可推导的,因为编译器不知道在执行类型推导时要选择哪个超载。

注意,编译器需要知道的F类型的函数的签名,也就是在这里,所以SFINAE做它的神奇:

is_same< 
    typename result_of<F(Args...)>::type, 
    int 
>::value, 

是绝对没有办法为它正确地推断类型从proxy(foo, 5)调用F,所以SFINAE不能踢。作为一个方面说明,注意到C++不能仅基于返回类型重载。因此,您将无法单独根据返回类型区分具有相同名称的两个函数。你需要以某种方式强制一个参数匹配,它将SFINAE输出非候选重载。

某种联系:Deducing the return type of a standalone function

,并从标准相关的报价,强调雷(感谢@TC指点出来):从一个函数调用[温度

14.8.2.1推导模板参数.deduct.call] /(6.2)

(6) When P is a function type, pointer to function type, or pointer to member function type:

  • (6.1) If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.

  • (6.2) If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.

+0

但为什么不尝试每一个,看看它会得到多少模板实例化/替代? 有没有办法解决这个问题,而没有明确的转换? – onqtam

+0

@onqtam我想这太复杂了,因为编译器的第一个参数'F'与第二个'Args ...'没有任何关系。我会试着想一个解决方法。 – vsoftco

+0

这个问题是可重现的没有参数 - 只有当使用返回类型...我想我应该把一个更简单的例子 – onqtam

2

在您的例子foo名一组的重载函数,和模板参数推导无法选择o ne超过另一个,因为它们都是相等的等级。

在推导出F之后,您的SFINAE约束检查才会启动,因此从重载解析集合中删除float foo(float)没有任何帮助。

假设你重命名函数返回floatfoof,那么你的例子将编译。但是,如果您尝试将proxyfoof作为函数参数进行调用,则代码将再次无法编译,这次是因为enable_if约束。

为了让您的例子在当前状态下进行编译,您必须消除歧义这foo要传递到proxy

proxy(static_cast<int(*)(int)>(foo), 5); 
+0

我想我还没有完全理解SFINAE,因为我认为它会帮助我在这里... – onqtam

相关问题