C++的杂七杂八:萃取函数(可调用体)的各种属性

/ 0评 / 0

Published by orzz.org(). (https://orzz.org/cxx-function-traits/)

在C++中,存在“可调用对象(callable objects)”这么一个概念。这里我直接摘录C++11标准《ISO/IEC 14882:2011》,§ 20.8.1 Definitions:

A callable type is a function object type (20.8) or a pointer to member.
A callable object is an object of a callable type.

同时,再根据 § 20.8 Function objects:

A function object type is an object type (3.9) that can be the type of the postfix-expression in a function call (5.2.2, 13.3.1.1). A function object is an object of a function object type. In the places where one would expect to pass a pointer to a function to an algorithmic template (Clause 25), the interface is specified to accept a function object. This not only makes algorithmic templates work with pointers to functions, but also enables them to work with arbitrary function objects.

我们可以总结出callable objects的基本定义:

  • 1. 是一个函数指针;
  • 2. 或者是一个具有operator()成员函数的类对象(仿函数);
  • 3. 或者是一个可被转换为函数指针的类对象;
  • 4. 或者是一个类成员(函数)指针。

  • 一个callable objects用起来就像下面这样:

    从上面我们可以看到,除了类成员指针之外,上面的定义里涉及到的对象均可以像一个函数那样做调用操作。另外,由于函数类型并不能直接用来定义对象,因此上面对可调用类型的定义里并没有包含函数类型。
    从实际使用的角度来说,如果我们需要萃取可调用体的各种属性,那么这个“可调用体”会和标准中的定义有些出入。我们至少需要包含以下类型:

  • 1. 普通函数类型及函数指针;
  • 2. 具有operator()成员函数的类对象(仿函数)或仿函数指针;
  • 3. 类成员函数指针;
  • 4. std::function。

  • 首先,我们写一个namespace,把detail和外部的function_traits隔离开,这样就可以在function_traits真正执行之前做一次decay:

    之后,通过impl的特化来处理各种情况:

    上面的实现里需要注意的几个地方如下:

  • 1. 使用decltype(&F::operator())将仿函数的operator()类型萃取出来,再重新丢到impl中递归处理;
  • 2. 参数表的变参(...)需要单独处理;
  • 3. 所有真正的萃取操作,都集中到了对函数类型R(P...)和R(P..., ...)的处理上;
  • 4. 注意类成员函数需要处理cv限定符(cv-qualifier);
  • 5. std::function的特化其实并不是必要的,对vc和gcc的stl来说,最开始的仿函数特化已经足够了。
  • Published by orzz.org(). (https://orzz.org/cxx-function-traits/)

    发表回复

    您的电子邮箱地址不会被公开。 必填项已用*标注

    此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据