我看到 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
适用于表达式。)
最佳答案
您的版本不适用于例如指向成员的指针。更接近但仍不准确的版本是:
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::thread
、std::bind
、std::function
)以难以捉摸的形式指定INVOKE(f, a0, a1, ..., aN) 伪表达式,不完全等同于 f(a0, a1, ... aN)
.从 std::result_of
是这些组件之一,实际上用于计算 INVOKE 的结果类型,这就是您注意到的差异。
因为没有std::invoke
与 std::result_of
一起出现类型特征我认为后者仅用于描述例如当您的代码调用它们时,相关标准库组件的返回类型。如果您想要一种简洁且 self 记录的写作方式,例如返回类型(对于可读性而言,这是一个非常有值(value)的目标,而不是到处撒 decltype
),那么我建议您编写自己的别名:
template<typename F, typename... A>
using ResultOf = decltype( std::declval<F>()(std::declval<A>()...) );
(如果您希望将别名用作 ResultOf<F(A...)>
而不是 ResultOf<F, A...>
,那么您需要一些机制来对函数签名进行模式匹配。)
与 std::result_of
不同,此别名的另一个好处是它对 SFINAE 友好。 .是的,这是它的另一个缺陷。 (公平地说,虽然这已经针对即将发布的标准进行了修改,并且实现已经在效仿。)
如果您使用这样的特性,您将不会丢失任何东西,因为您可以调整指向成员的指针,这要归功于 std::mem_fn
.
关于c++ - result_of<F(Args...> 和 decltype<f(args...)> 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15673792/