result_of <f(args ...>和decltype <f(args ...)>?</f(args ...)> </f(args ...>)之间有什么区别?

时间:2013-03-28 03:32:04

标签: c++ c++11

我看到std::async指定如下:

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适用于表达式。)

3 个答案:

答案 0 :(得分: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)根据难以捉摸的 INVOKE(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调整指向成员的指针。

答案 1 :(得分:5)

从功能的角度来看,没有任何区别。但是,decltype版本使用 trailing-return-type ,这与编程的观点有一点不同。

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

就我个人而言,我更喜欢使用decltype,因为它更强大并适用于任何实体,而result_of仅适用于可调用实体。因此,如果我使用decltype,我可以随处使用它。但是对于result_of,我偶尔会切换到decltype(也就是说,当实体可调用时)。请参阅我在所有函数的返回类型中使用decltype的{​​{3}}。

答案 2 :(得分:5)

您的问题已经存在差异:“我了解result_of适用于类型,而decltype适用于表达式。”

它们都提供相同的功能(std::result_of甚至实现了decltype现在而且您的示例的差异几乎不存在,因为您已经有必要的变量来构建表达式。

也就是说,当你只有类型时,差异归结为语法糖。考虑:

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

VS

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 ) >