函数对象(function object)[note 1]是一个程序设计的对象允许被当作普通函数来调用。

与之相区分:

  • functionoid(函数体对象)定义为“有一个主要方法”的对象(object),不要求是什么类型,只要能 “调用” 就行。例如:struct LessThan { bool compare(int a, int b) const { return a < b; } };
    • functor(仿函数)定义为:重载了 operator() 的类对象(class object)。在 C++ 里,functor 就是 function object。
      • lambda对象,生成一个匿名的 closure object,其类型叫 closure type
      • std::bind(...) 返回对象,更准确叫bind expression object。
      • std::function<R(Args...)> 对象,更准确叫 type-erased polymorphic function wrapper。通常也算functor。
      • C++20 CPO,Customization Point Object,即“定制点对象”。例如std::ranges::begin。CPO 的重点不是“可调用”,而是“可定制”。所以 CPO 不只是“一个 functor”,它还承担了统一定制入口的角色。
      • C++20 Niebloid,用于描述 C++20 ranges 中的算法实体,例如std::ranges::sort。Niebloid 的关键特征包括:不能显式指定模板实参;不参与普通ADL

函数对象与函数指针相比,有两个优点:第一是编译器可以内联执行函数对象的调用;第二是函数对象内部可以保持状态。

函数式程序设计语言还支持闭包,例如,first-class函数支持在其创建时用到的函数外定义的变量的值保持下来,成为一个函数闭包。

C++函数对象的实例

编辑

传统的C/C++函数指针:

#include <stdlib.h>

/* Callback function, returns < 0 if a < b, > 0 if a > b, 0 if a == b */
int compareInts(const void* a, const void* b)
{
  return *(const int *)a - *(const int *)b;
}
...
// prototype of qsort is
// void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *));
...
int main(void)
{
    int items[] = { 4, 3, 1, 2 };
    qsort(items, sizeof(items) / sizeof(items[0]), sizeof(items[0]), compareInts);
    return 0;
}

C++中,函数对象是定义了函数调用运算符的类对象,称作class type functor

// comparator predicate: returns true if a < b, false otherwise
struct IntComparator
{
  bool operator()(const int &a, const int &b) const
  {
    return a < b;
  }
};
...
// An overload of std::sort is:
template <class RandomIt, class Compare>
void sort(RandomIt first, RandomIt last, Compare comp);
...
int main()
{
    std::vector<int> items { 4, 3, 1, 2 };
    std::sort(items.begin(), items.end(), IntComparator());
    return 0;
}

除了类类型函数对象,还有其他类型的函数对象,如使用成员函数指针或模板。C++11允许使用具有闭包功能的匿名函数。

C++ STL中的函数对象

编辑

C++的STL中的众多algorithm,非常依赖于函数对象处理容器的元素。因此,STL预定义了许多函数对象、谓词(predicate)、以及用于复合(composite)函数对象的binder、member function adapter、 pointer to function adapters、 negaters、 function objects base structure。由于STL中的algorithm使用函数对象作为参数时,一般都是传值调用,所以函数对象应该仔细设计其复制构造函数

预定义的函数对象

编辑

C++98在头文件functional中定义了下述函数对象:

  • plus<type>() 结果为(param1 + param2)
  • minus<type>() 结果为(param1 - param2)
  • multiplies<type>() 结果为(param1 * param2)
  • divides<type>() 结果为(param1 / param2)
  • modulus<type>() 结果为(param1 % param2)

谓词(predicate)

编辑

返回布尔值(或者可以隐式转换为布尔值)的函数对象。用于STL中的algorithm时,谓词应该是无状态的( stateless)函数对象,即谓词的结果不依赖于内部的数据成员。这是因为STL中的algorithm不保证内部实现时对传入的谓词要复制多少次。 C++98在头文件functional中定义了下述谓词:

  • equal_to<type>() 结果为(param1 == param2)
  • not_equal_to<type>() 结果为(param1 != param2)
  • less<type>() 结果为 (param1 < param2)
  • greater<type>() 结果为(param1 > param2)
  • less_equal<type>() 结果为 (param1 <= param2)
  • greater_equal<type>() 结果为 (param1 >= param2)
  • logical_not<type>() 结果为 (!param1)
  • logical_and<type>() 结果为 (param1 && param2)
  • logical_or<type>() 结果为 (param1 || param2)

Function Adapter

编辑

用于组合(combine)、变换(transform)、操作(manipulate)函数对象、特定参数值、或者特定函数。进一步细分为:

Binder

编辑

C++98在头文件functional中定义了两个函数bind1st与bind2nd,返回值为binder1st、binder2nd类型。用于把二元函数对象分别绑定第一个、第二个参数后成为单元函数对象。

Negater

编辑

negate把一个作为谓词的函数对象取反。C++98在头文件functional中定义了两个函数not1与not2,返回值为unary_negate、binary_negate类型。

Member function adapter

编辑

Member function adapter用于把类的成员函数用作STL中的algorithm的参数。C++98在头文件functional中定义了:

  • 函数mem_fun,返回值为mem_fun_t类型,用于通过一个类对象指针来调用成员函数指针
  • 函数mem_fun_ref,返回值为mem_fun_ref_t类型,用于通过一个类对象引用来调用成员函数指针。

Pointer to function adapter

编辑

函数指针适配器(Pointer to function adapter)是把函数指针包装为一个函数对象,以便STL中的algorithm用函数对象作为统一的参数类型,不用再考虑以函数指针作为传入参数的情形。C++98在头文件functional中定义了:

  • 函数ptr_fun,返回值为pointer_to_unary_function类型,包装了一个单参数的函数指针。
  • 重载函数ptr_fun,返回值为pointer_to_binary_function类型,包装了一个双参数的函数指针。

Function Object Base

编辑

函数对象基类(Function Object Base)定义在头文件functional中,用作STL的预定义的与函数对象有关的各个类的基类,其中定义了几个类型,分别表示函数调用的各个参数类型、结果类型。

  • unary_function类,定义了2个类型:argument_type、result_type;
  • binary_function类,定义了3个类型:first_argument_type、second_argument_type、result_type;

C#

编辑

C#的函数对象是通过委托(delegate)声明的。

using System;
using System.Collections.Generic;

static int CompareFunction(int x, int y)
{
    return x - y;
}


List<int> items = new(4, 3, 1, 2);
Comparison<int> del = CompareFunction;
items.Sort(del);


using System;
using System.Collections.Generic;

List<int> items = new(4, 3, 1, 2);
items.Sort((x, y) => x - y);

JavaScript

编辑

JavaScript中,函数是头等对象,并且支持闭包。

function Accumulator(start) {
  let current = start
  return function (x) {
    return current += x
  }
}

用法:

let a = Accumulator(4)
let x = a(5)   // x has value 9
x = a(2)       // x has value 11

let b = Accumulator(42)
x = b(7)       // x has value 49 (current = 49 in closure b)
x = a(7)       // x has value 18 (current = 18 in closure a)

PowerShell

编辑

Windows PowerShell语言中,脚本块(script block)是可作为一个整体单元使用的语句集合或表达式集合。脚本块可以接收参数并返回值。脚本块是Microsoft .NET Framework类型System.Management.Automation.ScriptBlock的实例。

Function Get-Accumulator($x) {
    {
        param($y)
        return $x += $y
    }.GetNewClosure()
}
PS C:\> $a = Get-Accumulator 4
PS C:\> & $a 5
9
PS C:\> & $a 2
11
PS C:\> $b = Get-Accumulator 32
PS C:\> & $b 10
42

Python

编辑

Python程序设计中,函数是作为头等对象(first-class object),可以如同普通的字符串、数值、list等对象那样操作。这使得大部分编写函数对象都是不必须的。

任何对象定义了__call__()方法,就具有了可以当作函数调用的语法。例如下面的做累加的类[2]

class Accumulator(object):
    def __init__(self, n):
        self.n = n
    def __call__(self, x):
        self.n += x
        return self.n

一个使用例子:

 >>> a = Accumulator(4)
 >>> a(5)
 9
 >>> a(2)
 11
 >>> b = Accumulator(42)
 >>> b(7)
 49

因为函数就是对象,可当作局部变量定义、确定其属性(内部状态)、作为别的函数的返回值。[3]例如:

def Accumulator(n):
    def inc(x):
        inc.n += x
        return inc.n
    inc.n = n
    return inc

Python 3中,可以用函数闭包来创建函数对象:

def Accumulator(n):
    def inc(x):
        nonlocal n
        n += x
        return n
    return inc

注释

编辑
  1. ^ In C++, a functionoid is an object that has one major method, and a functor is a special case of a functionoid.[1] They are similar to a function object, but not the same.

参考文献

编辑
  1. ^ 33.15: What's the difference between a functionoid and a functor? 互联网档案馆存檔,存档日期2004-10-13.
  2. ^ Accumulator Generator. [2013-08-03]. (原始内容存档于2020-11-09). 
  3. ^ Python reference manual - Function definitions. [2013-08-03]. (原始内容存档于2020-12-15). 

进一步阅读

编辑
  • David Vandevoorde & Nicolai M Josuttis (2006). C++ Templates: The Complete Guide, ISBN 0-201-73484-2: Specifically, chapter 22 is devoted to function objects.

外部链接

编辑

📚 Artikel Terkait di Wikipedia

二分搜尋

来跟踪搜索边界。该过程可以用伪代码表示如下,其中变量名和类型与上文相同,floor为下取整函数,unsuccessful表示搜索失败时的特定返回值: function binary_search(A, n, T) is L := 0 R := n − 1 while L ≤ R do m := floor((L +

应用二进制接口

(页面存档备份,存于互联网档案馆)) for not breaking binary compatibility between releases of your library. Mac OS X ABI Function Call Guide (页面存档备份,存于互联网档案馆) Debian ARM

鄰近恆星列表

Trigonometric Parallaxes. Hipparcos Catalogue. Burgasser et al. 2000 Visual binary orbits and masses post Hipparcos (页面存档备份,存于互联网档案馆), Staffan Söderhjelm,

梅森旋转算法

an implementation of the Mersenne Twister (页面存档备份,存于互联网档案馆) C++ and binary function libraries for several platforms. Multithreaded. Includes Mersenne Twister

AA树

insert it into. output: A balanced version T including X. Do the normal binary tree insertion procedure. Set the result of the recursive call to the correct

聯星

聯星(英語:Binary star)是兩顆恆星組成的恆星系統,它們圍繞著共同的質心,在軌道上互繞。兩顆或兩顆以上恆星組成的系統稱為多星系統。這些系統,尤其是在距離地球較遠的時候,在肉眼觀看時往往只是單一的一個光點,然後通過其它管道觀測會顯示為兩顆或更多顆恆星。 聯星常與雙星(Double

Python

Python运行时服务 定制Python解释器 导入模块 Python语言服务 文本处理(英语:Text processing)服务 二进制数据(英语:Binary data)服务 数据类型 数值和数学模块 函数式编程模块 文件和目录访问 数据持久化 数据压缩和存档 文件格式 加密服务 通用操作系统服务 MS

MD5

63]:= {6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21} //Use binary integer part of the sines of integers as constants: for i from 0 to 63 k[i]