)和decltype的结果有什么不同?

时间:2021-12-23 18:51:38

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 )是typename std::result_of< f&(Args…)>::type。

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

(如果您想要使用别名作为结果 而不是结果 ,> (a…)>

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 )是typename std::result_of< f&(Args…)>::type。

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

(如果您想要使用别名作为结果 而不是结果 ,> (a…)>

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) >,据我所知。