105

我在理解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);
}

我真的看不出与以下代码的区别:

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

或者

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

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

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

我是否认为decltype和之间的唯一区别result_of是第一个需要表达而第二个不需要?

4

2 回答 2

88

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;
    };
于 2010-04-22T09:54:40.017 回答
12

如果您需要的类型不是函数调用,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 type 应命名该类型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...)>是绝对优越的。它更清晰、更短且正确支持更多F


除非,也就是说,您在不希望允许指向成员的指针的上下文中使用它,否则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

正确的用法应该是result_of_t<F&()>,但这是您不必记住的细节decltype

于 2016-03-07T00:04:24.933 回答