I see that std::async
is specified as follows:
我看到std::async指定如下:
template <class F, class... Args> // copied out of the standard
future<typename result_of<F(Args...)>::type>
async(F&& f, Args&&... args);
I had expected it to be declared like this:
我原以为会这样宣布:
template <class F, class... Args>
auto async(F&& f, Args&&... args) ->
future<decltype(forward<F>(f)(forward<Args>(args)...)>;
Would that be equivalent, or is there some way in which the use of result_of
is preferable to the use of decltype
? (I understand that result_of
works with types, while decltype
works with expressions.)
这是等价的吗?或者在某种程度上,使用result_of比使用decltype更可取?(我理解与类型一起工作的result_of,而decltype使用表达式。)
3 个解决方案
#1
11
Your version doesn't work with e.g. pointers to members. A closer, but still not exact version would be:
您的版本与成员的指针无关。更接近,但仍不准确的版本是:
template <class F, class... Args>
auto async(F&& f, Args&&... args)
-> future<decltype( ref(f)(forward<Args>(args)...) )>;
The only difference remaining with std::result_of
is that this forwards the functor as an lvalue (a problem your version also shares). In other words, the result of such a call (via an std::reference_wrapper<F>
) is typename std::result_of<F&(Args...)>::type
.
唯一的区别是std::result_of,它将函数作为一个lvalue(一个问题,您的版本也共享)。换句话说,这种调用的结果(通过std::reference_wrapper
This is an awkward situation where several components of the Standard library (to name a few, in addition to those we've just witnessed: std::thread
, std::bind
, std::function
) are specified in terms of an elusive INVOKE(f, a0, a1, ..., aN) pseudo-expression, which isn't exactly equivalent to f(a0, a1, ... aN)
. Since std::result_of
is one of those components, and serves in fact to compute the result type of INVOKE, that's the discrepancy you're noticing.
这是一个非常尴尬的情况,标准库的几个组件(除了我们刚才看到的那些:std::thread, std::bind, std::function)是在难以捉摸的调用中指定的(f, a0, a1,…,a)伪表达式,它与f(a0, a1,…一个)。由于std::result_of是其中一个组件,并且实际上是用来计算调用结果类型的,这就是您注意到的差异。
Because there is no std::invoke
that comes in tandem with the std::result_of
type trait I am of the opinion that the latter is only useful for describing e.g. the return types of the relevant Standard Library components, when your code calls them. If you want a concise and self-documenting way of writing e.g. a return type (a very worthy goal for readability, compared to sprinkling decltype
everywhere), then I recommend you write your own alias:
因为没有std::调用,它与std::result_of type trait一致,我认为后者只对描述相关标准库组件的返回类型(当代码调用它们时)有用。如果你想要一种简洁的、自我记录的写作方式,比如返回类型(这是一个非常值得阅读的目标,相比之下,到处都是这样的文章),那么我建议你写自己的别名:
template<typename F, typename... A>
using ResultOf = decltype( std::declval<F>()(std::declval<A>()...) );
(If you want the alias to be used as ResultOf<F(A...)>
instead of ResultOf<F, A...>
then you need a little bit of machinery to pattern match over the function signature.)
(如果您想要使用别名作为结果
An added benefit of this alias is that it is SFINAE friendly, unlike std::result_of
. Yes, that is one more of its flaws. (To be fair though this has been amended for the upcoming Standard and implementations are following suit already.)
这个别名的另一个好处是它是SFINAE友好的,不像std::result_of。是的,这是它的一个缺点。(公平地说,这已经为即将到来的标准和实现做了修改,现在已经开始执行了。)
You would not be missing anything if you were using such a trait because you can adapt pointers to members thanks to std::mem_fn
.
如果您使用这样的特性,您将不会丢失任何东西,因为您可以使用std::mem_fn来调整指向成员的指针。
#2
5
No difference at all from functional point of view. However, the decltype
version uses trailing-return-type, that is one difference from programming point of view.
从功能的角度来看,没有区别。但是,decltype版本使用的是trail- re类型,这与编程的观点不同。
In C++11, the std::result_of
is not absolutely necessary, one can use decltype
instead, like the way you've used. But std::result_of
is backward-compatible with third party libraries (older ones) such as Boost which has result_of
. I don't see much advantage, though.
在c++ 11中,std::result_of并不是绝对必要的,可以使用decltype,就像您使用的方法一样。但是std::result_of是向后兼容的,与第三方库(较老的库)兼容,例如Boost,它有result_of。不过,我觉得没什么好处。
Personally, I prefer to use decltype
as it is more powerful and works with any entities, whereas result_of
works with callable entities only. So if I use decltype
, I can use it everywhere. But with result_of
, I've to occasionally switch to decltype
(that is, when the entity is not callable). See this at github where I've used decltype
in return type of all functions.
就我个人而言,我倾向于使用decltype,因为它更强大,可以与任何实体一起工作,而result_of只适用于可调用实体。因此,如果我使用decltype,我可以在任何地方使用它。但是使用result_of,我偶尔会切换到decltype(也就是说,当实体不可调用时)。在github上看到这个,我在这里使用了decltype作为所有函数的返回类型。
#3
5
You already had the difference in your questions: "I understand that result_of
works with types, while decltype
works with expressions."
您的问题已经有了不同:“我理解与类型一起工作的result_of,而decltype使用表达式。”
They both provide the same functionality (std::result_of
is even implemented in terms of decltype
nowadays) and the difference for your example is mostly non-existent, because you already have the necessary variables to build an expression.
它们都提供了相同的功能(std::result_of现在甚至在decltype中实现了),而您的示例的差异几乎不存在,因为您已经有了构建表达式所需的变量。
That said, the difference boils down to syntactic sugar for when you only have the types. Consider:
也就是说,当你只有这些类型的时候,它们的区别可以归结为语法糖。考虑:
typename std::result_of< F( A, B, C ) >::type
vs.
vs。
decltype( std::declval<F>()( std::declval<A>(), std::declval<B>(), std::declval<C>() )
And just remember that std::result_of
is an option in those cases.
记住std::result_of是这些情况下的一个选项。
Note that there are also cases where decltype
can be used in a way that std::result_of
can't. Consider decltype( a + b )
, you can not find an F
to create an equivalent std::result_of< F( A, B ) >
as far as I know.
请注意,也有一些例子可以用std::result_of不能的方式使用decltype。考虑decltype(a + b),您不能找到一个F来创建一个等效的std::result_of< F(a, b) >,据我所知。
#1
11
Your version doesn't work with e.g. pointers to members. A closer, but still not exact version would be:
您的版本与成员的指针无关。更接近,但仍不准确的版本是:
template <class F, class... Args>
auto async(F&& f, Args&&... args)
-> future<decltype( ref(f)(forward<Args>(args)...) )>;
The only difference remaining with std::result_of
is that this forwards the functor as an lvalue (a problem your version also shares). In other words, the result of such a call (via an std::reference_wrapper<F>
) is typename std::result_of<F&(Args...)>::type
.
唯一的区别是std::result_of,它将函数作为一个lvalue(一个问题,您的版本也共享)。换句话说,这种调用的结果(通过std::reference_wrapper
This is an awkward situation where several components of the Standard library (to name a few, in addition to those we've just witnessed: std::thread
, std::bind
, std::function
) are specified in terms of an elusive INVOKE(f, a0, a1, ..., aN) pseudo-expression, which isn't exactly equivalent to f(a0, a1, ... aN)
. Since std::result_of
is one of those components, and serves in fact to compute the result type of INVOKE, that's the discrepancy you're noticing.
这是一个非常尴尬的情况,标准库的几个组件(除了我们刚才看到的那些:std::thread, std::bind, std::function)是在难以捉摸的调用中指定的(f, a0, a1,…,a)伪表达式,它与f(a0, a1,…一个)。由于std::result_of是其中一个组件,并且实际上是用来计算调用结果类型的,这就是您注意到的差异。
Because there is no std::invoke
that comes in tandem with the std::result_of
type trait I am of the opinion that the latter is only useful for describing e.g. the return types of the relevant Standard Library components, when your code calls them. If you want a concise and self-documenting way of writing e.g. a return type (a very worthy goal for readability, compared to sprinkling decltype
everywhere), then I recommend you write your own alias:
因为没有std::调用,它与std::result_of type trait一致,我认为后者只对描述相关标准库组件的返回类型(当代码调用它们时)有用。如果你想要一种简洁的、自我记录的写作方式,比如返回类型(这是一个非常值得阅读的目标,相比之下,到处都是这样的文章),那么我建议你写自己的别名:
template<typename F, typename... A>
using ResultOf = decltype( std::declval<F>()(std::declval<A>()...) );
(If you want the alias to be used as ResultOf<F(A...)>
instead of ResultOf<F, A...>
then you need a little bit of machinery to pattern match over the function signature.)
(如果您想要使用别名作为结果
An added benefit of this alias is that it is SFINAE friendly, unlike std::result_of
. Yes, that is one more of its flaws. (To be fair though this has been amended for the upcoming Standard and implementations are following suit already.)
这个别名的另一个好处是它是SFINAE友好的,不像std::result_of。是的,这是它的一个缺点。(公平地说,这已经为即将到来的标准和实现做了修改,现在已经开始执行了。)
You would not be missing anything if you were using such a trait because you can adapt pointers to members thanks to std::mem_fn
.
如果您使用这样的特性,您将不会丢失任何东西,因为您可以使用std::mem_fn来调整指向成员的指针。
#2
5
No difference at all from functional point of view. However, the decltype
version uses trailing-return-type, that is one difference from programming point of view.
从功能的角度来看,没有区别。但是,decltype版本使用的是trail- re类型,这与编程的观点不同。
In C++11, the std::result_of
is not absolutely necessary, one can use decltype
instead, like the way you've used. But std::result_of
is backward-compatible with third party libraries (older ones) such as Boost which has result_of
. I don't see much advantage, though.
在c++ 11中,std::result_of并不是绝对必要的,可以使用decltype,就像您使用的方法一样。但是std::result_of是向后兼容的,与第三方库(较老的库)兼容,例如Boost,它有result_of。不过,我觉得没什么好处。
Personally, I prefer to use decltype
as it is more powerful and works with any entities, whereas result_of
works with callable entities only. So if I use decltype
, I can use it everywhere. But with result_of
, I've to occasionally switch to decltype
(that is, when the entity is not callable). See this at github where I've used decltype
in return type of all functions.
就我个人而言,我倾向于使用decltype,因为它更强大,可以与任何实体一起工作,而result_of只适用于可调用实体。因此,如果我使用decltype,我可以在任何地方使用它。但是使用result_of,我偶尔会切换到decltype(也就是说,当实体不可调用时)。在github上看到这个,我在这里使用了decltype作为所有函数的返回类型。
#3
5
You already had the difference in your questions: "I understand that result_of
works with types, while decltype
works with expressions."
您的问题已经有了不同:“我理解与类型一起工作的result_of,而decltype使用表达式。”
They both provide the same functionality (std::result_of
is even implemented in terms of decltype
nowadays) and the difference for your example is mostly non-existent, because you already have the necessary variables to build an expression.
它们都提供了相同的功能(std::result_of现在甚至在decltype中实现了),而您的示例的差异几乎不存在,因为您已经有了构建表达式所需的变量。
That said, the difference boils down to syntactic sugar for when you only have the types. Consider:
也就是说,当你只有这些类型的时候,它们的区别可以归结为语法糖。考虑:
typename std::result_of< F( A, B, C ) >::type
vs.
vs。
decltype( std::declval<F>()( std::declval<A>(), std::declval<B>(), std::declval<C>() )
And just remember that std::result_of
is an option in those cases.
记住std::result_of是这些情况下的一个选项。
Note that there are also cases where decltype
can be used in a way that std::result_of
can't. Consider decltype( a + b )
, you can not find an F
to create an equivalent std::result_of< F( A, B ) >
as far as I know.
请注意,也有一些例子可以用std::result_of不能的方式使用decltype。考虑decltype(a + b),您不能找到一个F来创建一个等效的std::result_of< F(a, b) >,据我所知。