14

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

4

3 回答 3

11

您的版本不适用于例如指向成员的指针。更接近但仍不准确的版本是:

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

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

这是一个尴尬的情况,标准库的几个组件(仅举几例,除了我们刚刚见证的组件:std::thread, std::bind, std::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.

于 2013-03-29T21:27:33.370 回答
5

从功能的角度来看完全没有区别。但是,该decltype版本使用trailing-return-type,这是从编程角度来看的一个区别。

在 C++11 中,std::result_of不是绝对必要的,可以使用decltype,就像您使用的方式一样。但std::result_of向后兼容第三方库(较旧的库),例如具有result_of. 不过我看不出有多大优势。

就个人而言,我更喜欢使用decltype它,因为它更强大并且适用于任何实体,而result_of仅适用于可调用实体。因此,如果我使用decltype,我可以在任何地方使用它。但是result_of,我不得不偶尔切换到decltype(即当实体不可调用时)。在 github上看到这个,我decltype在所有函数的返回类型中都使用了这个。

于 2013-03-28T03:36:58.420 回答
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 ) >

于 2013-03-28T07:00:27.513 回答