2013-03-28 403 views
14

我看到std::async规定如下:result_of <F(Args...>和decltype <f(args...)>有什么区别?

template <class F, class... Args>     // copied out of the standard 
future<typename result_of<F(Args...)>::type> 
async(F&& f, Args&&... args); 

我预期它声明如下:

template <class F, class... Args> 
auto async(F&& f, Args&&... args) -> 
    future<decltype(forward<F>(f)(forward<Args>(args)...)>; 

请问这是等价的,或者是有一些方式,其中使用result_of比使用decltype更可取? (据我所知,result_of适用于类型,而decltype适用于表达式。)

+0

是否用'result_of'指定_或_implemented_?因为这可能只是实现它的家伙的心血来潮,或者它可能已经在'decltype'之前实现到目标编译器。在Apple的libC++中,它既不使用。 – zneak 2013-03-28 04:03:48

+0

@zneak:我展示的声明被复制出标准,所以'std :: async'是通过'result_of'指定的。实现可以做任何他们喜欢的事情,只要它们提供的行为与指定的行为相同即可。 – KnowItAllWannabe 2013-03-28 06:03:03

+0

只要知道'std :: result_of'语法有一些[不幸的含义](http://stackoverflow.com/a/15489789/500104)。 – Xeo 2013-03-28 07:44:15

回答

11

您的版本不适用于例如指向成员。再仔细,但仍然没有确切的版本是:

template <class F, class... Args> 
auto async(F&& f, Args&&... args) 
-> future<decltype(ref(f)(forward<Args>(args)...))>; 

std::result_of剩下的唯一的区别是,这个转发仿函数作为一个左值(一个问题,你的版本也万股)。换句话说,这种呼叫的结果(通过std::reference_wrapper<F>)是typename std::result_of<F&(Args...)>::type

这是一个尴尬的局面,其中标准库的几个组成部分(仅举几例,除了那些我们刚刚见证:std::threadstd::bindstd::function)在一个难以捉摸的援引术语规定(F, a0,a1,...,aN)伪表达式,它不完全等同于f(a0, a1, ... aN)。由于std::result_of是其中一个组件,并且实际上用于计算结果类型INVOKE,这就是您注意到的差异。

因为没有std::invokestd::result_of类型特征串联,我认为后者仅用于描述例如当您的代码调用它们时,相关标准库组件的返回类型。如果你想要一个简洁而自我记录的写作方式,例如返回类型(一个非常有价值的目标是为了便于阅读,比喷灌decltype无处不在),那么我建议你写你自己的别名:

template<typename F, typename... A> 
using ResultOf = decltype(std::declval<F>()(std::declval<A>()...)); 

(如果你想别名被用作ResultOf<F(A...)>代替ResultOf<F, A...>那么你需要一些机器来模式匹配功能签名。)

这个别名的一个额外的好处是它是SFINAE友好的,不像std::result_of。是的,这是它的另一个缺陷。 (公平地说,虽然已经对即将推出的标准进行了修改,但实施已经进行了相应的修改。)

如果您使用这样的特性,您可以使用指针,因为您可以修改指向成​​员的指针std::mem_fn

+0

我修改了原始代码,以便'decltype'版本将'std :: forward'应用于'f',因此推测可以消除所有函数对象都在左值处理的问题。感谢您指出了这一点。 – KnowItAllWannabe 2013-03-30 04:48:31

+0

我接受了这个答案,因为我认为'decltype'版本不支持指向成员的观察是很重要的。 – KnowItAllWannabe 2013-04-01 17:32:48

5

从功能上看,没有任何区别。然而,decltype版本使用尾随返回类型,这是从编程的角度的一个区别。

在C++ 11中,std::result_of不是绝对必要的,可以使用decltype代替,就像您使用的方式一样。但std::result_of向后兼容第三方库(较旧的),如具有result_of的Boost。虽然我没有看到太多优势。

就个人而言,我更喜欢使用decltype因为它是更强大,并与任何实体的作品,而作品result_of只调用实体。所以如果我使用decltype,我可以在任何地方使用它。但与result_of,我不得不偶尔切换到decltype(即,当实体是而不是可调用)。请参阅this at github,我已使用decltype作为所有功能的返回类型。

+0

另一个编程区别是'decltype'版本需要使用'forward',而'return_of'版本显然不需要。 – KnowItAllWannabe 2013-03-28 03:39:17

+0

@KnowItAllWannabe:正如你已经注意到自己(在问题中),'std :: result_of'与* types *一起工作,所以没有什么可以转发。 – Nawaz 2013-03-28 03:40:46

+0

我想你的意思是'std :: result_of',你写了'std :: result_type'。 – KnowItAllWannabe 2013-03-28 03:48:31

5

您的问题已经有所不同了:“我知道result_of适用于类型,而decltype适用于表达式。”

它们都提供相同的功能(std::result_of甚至在decltype时下方面实现的),并为您的例如的差异主要是不存在的,因为你已经有了必需的变量构建表达式。

也就是说,差异归结为当你只有类型的语法糖。试想一下:

typename std::result_of< F(A, B, C) >::type 

decltype(std::declval<F>()(std::declval<A>(), std::declval<B>(), std::declval<C>()) 

而只记得std::result_of是在这些情况下的一个选项。

请注意,有些情况下decltype可以以std::result_of不能使用的方式使用。就我所知,考虑decltype(a + b),您无法找到F来创建等效的std::result_of< F(A, B) >

+1

你真的想在每个模板参数而不是'std :: forward'上使用'std :: declval'吗? – KnowItAllWannabe 2013-03-29 17:48:26

+0

如果您只有**类型**,请重新阅读答案。没有这种类型的变量,你不能使用'std :: forward',因为它需要一个参数。 – 2013-03-29 21:01:33

+1

Downvoter:为什么? – 2013-03-29 21:06:09

相关问题