std::result_of和decltype的区别

时间:2022-03-29 20:10:40

I have some trouble understanding the need for std::result_of in C++0x. If I understood correctly, result_of is used to obtain the resulting type of invoking a function object with certain types of parameters. For example:

我在理解std的需要方面有些困难:在c++ 0x中使用result_of。如果理解正确,那么使用result_of来获取调用具有特定类型参数的函数对象的结果类型。例如:

template <typename F, typename Arg>
typename std::result_of<F(Arg)>::type
invoke(F f, Arg a)
{
    return f(a);
}

I don't really see the difference with the following code:

我看不出下面的代码有什么不同:

template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(f(a)) //uses the f parameter
{
    return f(a);
}

or

template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(F()(a)); //"constructs" an F
{
    return f(a);
}

The only problem I can see with these two solutions is that we need to either:

我能看到的这两个解决方案的唯一问题是我们需要:

  • have an instance of the functor to use it in the expression passed to decltype.
  • 在传递给decltype的表达式中使用该函数的实例。
  • know a defined constructor for the functor.
  • 知道函数的定义构造函数。

Am I right in thinking that the only difference between decltype and result_of is that the first one needs an expression whereas the second does not?

我是否正确地认为,decltype和result_of之间的唯一区别就是第一个需要一个表达式,而第二个不需要呢?

2 个解决方案

#1


79  

result_of was introduced in Boost, and then included in TR1, and finally in C++0x. Therefore result_of has an advantage that is backward-compatible (with a suitable library).

在Boost中引入了result_of,然后在TR1中包含,最后在c++ 0x中包含。因此,result_of具有向后兼容的优势(具有合适的库)。

decltype is an entirely new thing in C++0x, does not restrict only to return type of a function, and is a language feature.

decltype在c++ 0x中是一个全新的东西,它不仅限制返回函数的类型,而且是一种语言特性。


Anyway, on gcc 4.5, result_of is implemented in terms of decltype:

总之,在gcc 4.5中,result_of是按照解密类型实现的:

  template<typename _Signature>
    class result_of;

  template<typename _Functor, typename... _ArgTypes>
    struct result_of<_Functor(_ArgTypes...)>
    {
      typedef
        decltype( std::declval<_Functor>()(std::declval<_ArgTypes>()...) )
        type;
    };

#2


10  

If you need the type of something that isn't something like a function call, std::result_of just doesn't apply. decltype() can give you the type of any expression.

如果您需要的类型不是函数调用,那么std::result_of就不适用。decltype()可以给你任何表达式的类型。

If we restrict ourselves to just the different ways of determining the return type of a function call (between std::result_of_t<F(Args...)> and decltype(std::declval<F>()(std::declval<Args>()...)), then there is a difference.

如果我们只局限于确定函数调用的返回类型的不同方法(std:: result_of_t 和decltype(std: declval (): std: declval ()))之间,那么就有区别了。 (args…)>

std::result_of<F(Args...) is defined as:

std::result_of < F(Args…)被定义为:

If the expression INVOKE (declval<Fn>(), declval<ArgTypes>()...) is well formed when treated as an unevaluated operand (Clause 5), the member typedef type shall name the type decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...)); otherwise, there shall be no member type.

如果表达式调用(declval (), declval ()…)在作为一个未赋值的操作数时格式良好(第5条),那么成员类型def类型应将类型命名为decltype(INVOKE) (declval (), declval ()…));否则,不存在成员类型。

The difference between result_of<F(Args..)>::type and decltype(std::declval<F>()(std::declval<Args>()...) is all about that INVOKE. Using declval/decltype directly, in addition to being quite a bit longer to type, is only valid if F is directly callable (a function object type or a function or a function pointer). result_of additionally supports pointers to members functions and pointers to member data.

::type和decltype(std: declval (): std: declval ()…)的合成结果之间的差异就是这个调用。除非F是直接可调用的(函数对象类型、函数类型或函数指针),否则直接使用declval/decltype,除了要花很长一段时间才能打字。此外,result_of还支持指向成员函数的指针和指向成员数据的指针。 (args.)>

Initially, using declval/decltype guaranteed a SFINAE-friendly expression, whereas std::result_of could give you a hard error instead of a deduction failure. That has been corrected in C++14: std::result_of is now required to be SFINAE-friendly (thanks to this paper).

一开始,使用declval/decltype可以保证一个SFINAE-friendly表达式,而std::result_of可以给你一个硬错误而不是演绎失败。C+ 14: std::result_of现在需要对sfinae友好(感谢本文)。

So on a conforming C++14 compiler, std::result_of_t<F(Args...)> is strictly superior. It's clearer, shorter, and correctly supports more Fs.

因此,在一个c++ 14编译器上,std: result_of_t 是绝对优越的。它更清晰,更短,正确地支持更多的Fs。 (args…)>


Unless, that is, you're using it in a context where you don't want to allow pointers to members, so std::result_of_t would succeed in a case where you might want it to fail.

With exceptions. While it supports pointers to members, result_of will not work if you try to instantiate an invalid type-id. These would include a function returning a function or taking abstract types by value. Ex.:

‡例外。虽然它支持指向成员的指针,但是如果您试图实例化无效的类型id,那么result_of将不起作用。这些函数包括返回一个函数的函数或按值提取抽象类型。例:

template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }

int answer() { return 42; }

call(answer); // nope

The correct usage would've been result_of_t<F&()>, but that's a detail you don't have to remember with decltype.

正确的用法应该是result_of_t< f&()>,但是您不需要用decltype来记住这个细节。

#1


79  

result_of was introduced in Boost, and then included in TR1, and finally in C++0x. Therefore result_of has an advantage that is backward-compatible (with a suitable library).

在Boost中引入了result_of,然后在TR1中包含,最后在c++ 0x中包含。因此,result_of具有向后兼容的优势(具有合适的库)。

decltype is an entirely new thing in C++0x, does not restrict only to return type of a function, and is a language feature.

decltype在c++ 0x中是一个全新的东西,它不仅限制返回函数的类型,而且是一种语言特性。


Anyway, on gcc 4.5, result_of is implemented in terms of decltype:

总之,在gcc 4.5中,result_of是按照解密类型实现的:

  template<typename _Signature>
    class result_of;

  template<typename _Functor, typename... _ArgTypes>
    struct result_of<_Functor(_ArgTypes...)>
    {
      typedef
        decltype( std::declval<_Functor>()(std::declval<_ArgTypes>()...) )
        type;
    };

#2


10  

If you need the type of something that isn't something like a function call, std::result_of just doesn't apply. decltype() can give you the type of any expression.

如果您需要的类型不是函数调用,那么std::result_of就不适用。decltype()可以给你任何表达式的类型。

If we restrict ourselves to just the different ways of determining the return type of a function call (between std::result_of_t<F(Args...)> and decltype(std::declval<F>()(std::declval<Args>()...)), then there is a difference.

如果我们只局限于确定函数调用的返回类型的不同方法(std:: result_of_t 和decltype(std: declval (): std: declval ()))之间,那么就有区别了。 (args…)>

std::result_of<F(Args...) is defined as:

std::result_of < F(Args…)被定义为:

If the expression INVOKE (declval<Fn>(), declval<ArgTypes>()...) is well formed when treated as an unevaluated operand (Clause 5), the member typedef type shall name the type decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...)); otherwise, there shall be no member type.

如果表达式调用(declval (), declval ()…)在作为一个未赋值的操作数时格式良好(第5条),那么成员类型def类型应将类型命名为decltype(INVOKE) (declval (), declval ()…));否则,不存在成员类型。

The difference between result_of<F(Args..)>::type and decltype(std::declval<F>()(std::declval<Args>()...) is all about that INVOKE. Using declval/decltype directly, in addition to being quite a bit longer to type, is only valid if F is directly callable (a function object type or a function or a function pointer). result_of additionally supports pointers to members functions and pointers to member data.

::type和decltype(std: declval (): std: declval ()…)的合成结果之间的差异就是这个调用。除非F是直接可调用的(函数对象类型、函数类型或函数指针),否则直接使用declval/decltype,除了要花很长一段时间才能打字。此外,result_of还支持指向成员函数的指针和指向成员数据的指针。 (args.)>

Initially, using declval/decltype guaranteed a SFINAE-friendly expression, whereas std::result_of could give you a hard error instead of a deduction failure. That has been corrected in C++14: std::result_of is now required to be SFINAE-friendly (thanks to this paper).

一开始,使用declval/decltype可以保证一个SFINAE-friendly表达式,而std::result_of可以给你一个硬错误而不是演绎失败。C+ 14: std::result_of现在需要对sfinae友好(感谢本文)。

So on a conforming C++14 compiler, std::result_of_t<F(Args...)> is strictly superior. It's clearer, shorter, and correctly supports more Fs.

因此,在一个c++ 14编译器上,std: result_of_t 是绝对优越的。它更清晰,更短,正确地支持更多的Fs。 (args…)>


Unless, that is, you're using it in a context where you don't want to allow pointers to members, so std::result_of_t would succeed in a case where you might want it to fail.

With exceptions. While it supports pointers to members, result_of will not work if you try to instantiate an invalid type-id. These would include a function returning a function or taking abstract types by value. Ex.:

‡例外。虽然它支持指向成员的指针,但是如果您试图实例化无效的类型id,那么result_of将不起作用。这些函数包括返回一个函数的函数或按值提取抽象类型。例:

template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }

int answer() { return 42; }

call(answer); // nope

The correct usage would've been result_of_t<F&()>, but that's a detail you don't have to remember with decltype.

正确的用法应该是result_of_t< f&()>,但是您不需要用decltype来记住这个细节。