std :: result_of和decltype之间的区别

Luc*_*lle 97 c++ result-of decltype c++11

我在理解std::result_ofC++ 0x中的需求时遇到了一些麻烦.如果我理解正确,result_of则用于获取调用具有某些类型参数的函数对象的结果类型.例如:

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

我真的没有看到与以下代码的区别:

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

要么

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

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

  • 有一个仿函数的实例在传递给decltype的表达式中使用它.
  • 知道仿函数的定义构造函数.

难道我就在想,唯一的区别decltyperesult_of是而第二个不第一个需要表达?

ken*_*ytm 84

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

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


无论如何,在gcc 4.5上,result_of实现的是decltype:

  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;
    };
Run Code Online (Sandbox Code Playgroud)

  • 据我所知,`decltype`更丑陋但也更强大.`result_of`只能用于可调用的类型,并且需要类型作为参数.例如,你不能在这里使用`result_of`:`template <typename T,typename U> auto sum(T t,U u) - > decltype(t + u);`如果参数可以是算术类型(没有函数`F`,你可以定义`F(T,U)`代表`t + u`.对于用户定义的类型你可以.以同样的方式(我还没有真正玩过它)我想象如果不使用绑定器或lambda,`result_of`可能很难使用成员方法 (4认同)
  • @RobertMason:可以使用`std :: declval`检索那些参数,就像我上面显示的代码一样.当然,这很难看:) (3认同)
  • @Luc:是的.:) (晚了!) (2认同)
  • 需要注意的是,decltype需要使用AFAIK调用函数的参数,因此如果没有result_of <>,在不依赖具有有效默认构造函数的参数的情况下获取模板返回的类型是很尴尬的. (2认同)
  • 另请注意:从 C++17 起,不推荐使用“result_of”及其帮助器类型“result_of_t”,转而使用“invoke_result”和“invoke_result_t”,从而减轻了前者的一些限制。这些列在 https://en.cppreference.com/w/cpp/types/result_of 的底部。 (2认同)

Bar*_*rry 11

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

如果我们仅限于确定函数调用的返回类型的不同方式(在std::result_of_t<F(Args...)>和之间decltype(std::declval<F>()(std::declval<Args>()...)),则存在差异.

std::result_of<F(Args...) 定义为:

如果表达式 INVOKE (declval<Fn>(), declval<ArgTypes>()...)在作为未评估的操作数处理时形成良好(第5条),则成员typedef类型应为该类型命名,decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...)); 否则不应有成员类型.

result_of<F(Args..)>::type和之间的区别就在decltype(std::declval<F>()(std::declval<Args>()...)于此INVOKE.使用declval/ decltype直接,除了输入的时间要长得多之外,只有在F可直接调用(函数对象类型或函数或函数指针)时才有效.result_of另外还支持指向成员函数的指针和指向成员数据的指针.

最初,使用declval/ decltype保证SFINAE友好的表达式,但std::result_of可能会给你一个硬错误而不是扣除失败.这已在C++ 14中得到纠正:std::result_of现在需要SFINAE友好(感谢本文).

因此,在符合标准的C++ 14编译器上,std::result_of_t<F(Args...)>是非常优越的.它更清晰,更短,更正确支持更多Fs .


除非,即在您不希望允许指向成员的指针的上下文中使用它,否则std::result_of_t在您可能希望它失败的情况下会成功.

有例外.虽然它支持指向成员的指针,result_of但如果您尝试实例化无效的type-id,则无效.这些将包括一个返回函数或按值抽取类型的函数.例:

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

int answer() { return 42; }

call(answer); // nope
Run Code Online (Sandbox Code Playgroud)

正确的用法是result_of_t<F&()>,但这是一个你不必记住的细节decltype.