2014-09-24 71 views
2

以下代码中的函数invoke是调用另一个函数/函数/ lambda的简单包装,因此invoke(f,args...)等于f(args...)。 (这背后的原因是也有成员函数过载,从而允许这两种用法的一般化的语法。)从仿函数模板参数中推导可变参数和返回类型(特定于MSVC)

此实现工作在克++:

template <class Fn, class ...Args> 
auto invoke(Fn f, Args ...args) -> decltype(f(args...)) { 
    return f(args...); 
} 

int y = invoke([](int x){ return x+1; }, 42); // y = 43 

Demo

然而,MSVC 2012(十一月CTP)抱怨:

Error: C2893: Failed to specialize function template 'unknown-type invoke(Fn,Args...)' 
With the following template arguments: 
'main::<lambda_687537b292ffb7afcfd8f8fc292d6e73>' 
'int' 

(请注意,在错误信息的int来自42被传递给invoke,而不是来自lambda的论点。我通过传递与invoke不同的东西来检查此问题。)

我该如何解决这个问题以便与MSVC 2012(Nov CTP)一起使用?

的资料我尝试:

  • 当我改变可变参数模板参数的单个参数(但仍然是一个模板参数,即除去在上面的代码中的所有...),代码编译。但我需要支持任何数量的参数。

  • 它还编译,如果我用非通用的int返回类型替换尾随返回类型。但显然我想支持泛型返回类型。

  • 如果我传递函数指针而不是lambda表达式,行为不会改变。所以它与lambda无关。例如错误消息:

    Error: C2893: Failed to specialize function template 'unknown-type invoke(Fn,Args...)' 
    With the following template arguments: 
    'int (__cdecl *)(int)' 
    'double' 
    
+0

在Visual Studio 2013中实现了可变参数模板。请参阅[Support for C++ 11 Features](http://msdn.microsoft.com/zh-cn/library/hh567368.aspx) – 2014-09-24 00:49:04

+0

“'invoke(f, args ...)'等于'f(args ...)'“。对于当前定义的'invoke','invoke(f,std :: move(x))'不等于'f(std :: move(x))'。您需要通过使用通用/转发引用和“std :: forward”来转发参数。 – 2014-09-24 00:51:41

+0

@JonathanPotter他们已被添加到MSVC 2012年11月CTP补丁 – leemes 2014-09-24 00:51:43

回答

2

尝试使用typename result_of<F(Args...)>::type。 (我的意思是这种情况:使用类型而不是数值)。

这不支持标准下的SFINAE,但是如果可能在一半兼容的C++ 11编译器中工作。

如果你的编译器没有爆炸,也可以使用Args&&...和perfect。

+0

不错!正是我在找什么。似乎工作(现在)。 – leemes 2014-09-24 01:04:45