std :: result_of简单函数

时间:2012-07-13 12:45:41

标签: c++ c++11 std result-of

#include <iostream>
#include <type_traits>

double f(int i)
{
        return i+0.1;
}

struct F
{
        public:
        double operator ()(int i) { return i+0.1; }
};

int
main(int, char**)
{
        std::result_of<F(int)>::type x;     // ok
        // std::result_of<f(int)>::type x; // error: template argument 1 is invalid
        x = 0.1;
        std::cerr << x << std::endl;
}

请解释为什么std::result_of<f(int)>::type x;无效......

cppreference说“(std::result_of)在编译类型中减去函数调用表达式的返回类型。”。

有什么问题?

1 个答案:

答案 0 :(得分:25)

std::result_of<T>要求T成为一种类型 - 但不仅仅是任何类型。 T必须是函数类型,因此将使用result_of的部分特化:

template <class Fn, class... ArgTypes> struct result_of<Fn(ArgTypes...)>;

这样:

decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...))

格式正确(C ++ 11 20.9.7.6)。 (INVOKE在20.8.2中定义。)

std::result_of<f(int)>不起作用的原因是因为f不是类型 - 它是函数类型的实例。要将x声明为应用于f的{​​{1}}的返回类型,只需写下:

int

或者您更喜欢硬编码decltype(f(int{})) x;

int

如果需要decltype(f(32)) x; 的类型,请使用:

f

在提供的代码using FuncPtr = decltype(f); 中(即,不是小写F)但是是一个类型,因此f定义了一个表示返回F(int)接受的函数的类型一个F作为参数。显然,这不是F! int的类型是一个结构,其实例可以使用函数调用运算符。 F也没有明确或隐含的构造函数也使用F等。这怎么办?简答:模板“魔术”。

基本上,int的定义采用类型std::result_of并将返回类型与参数类型分开,以便它可以确定INVOKE()的哪种情况允许它起作用。 INVOKE的案例是:

  1. F是指向某个类T
  2. 的成员函数的指针
  3. 如果只有一个参数,则F是指向T类数据成员的指针,或
  4. F的实例可以用作函数,即
  5. F(int)

    可以是正常的函数调用或某种类型的函子(例如,像你的例子)。

    确定后,declval<F>()(declval<int>()) 可以确定有效表达式的返回类型。这是通过result_of的{​​{1}}成员返回的内容。

    关于这一点的美妙之处在于result_of的用户不需要知道这实际上是如何工作的。唯一需要了解的是type需要一个函数TYPE。如果使用的代码不是代码中的类型(例如,result_of),则需要使用result_of来获取具有此类型的表达式的类型。

    最后,f不能被视为类型的部分原因是因为模板参数也允许常量值,decltype是常量函数指针值。这很容易证明(使用问题的f定义):

    f

    以后:

    f

    因此要获取正确调用template <double Op(int)> double invoke_op(int i) { return Op(i); } 并使用某些std::cout << invoke_op<f>(10) << std::endl; 的表达式的返回值类型,可以写:

    f

    (注意:永远不会调用int:编译器只使用decltype(f(int{})) 中的表达式来确定其结果,即在此实例中的返回值。)