函式對象
函式對象(function object)[note 1]是一個程式設計的對象允許被當作普通函式來呼叫。
函式對象與函式指標相比,有兩個優點:第一是編譯器可以行內執行函式對象的呼叫;第二是函式對象內部可以保持狀態。
函數式程式設計語言還支援閉包,例如,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;
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
注釋
編輯參考文獻
編輯- ^ 33.15: What's the difference between a functionoid and a functor? 網際網路檔案館的存檔,存檔日期2004-10-13.
- ^ Accumulator Generator. [2013-08-03]. (原始內容存檔於2020-11-09).
- ^ 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.
外部連結
編輯- Function Objects (STL) by Gabriel&Andreas Fleseriu&Masur on February 22nd, 2006 (頁面存檔備份,存於網際網路檔案館)
- Description from the Portland Pattern Repository(頁面存檔備份,存於網際網路檔案館)
- C++ Advanced Design Issues - Asynchronous C++ (頁面存檔備份,存於網際網路檔案館) by Kevlin Henney
- The Function Pointer Tutorials (頁面存檔備份,存於網際網路檔案館) by Lars Haendel (2000/2001)
- Article "Generalized Function Pointers" by Herb Sutter
- Generic Algorithms for Java (頁面存檔備份,存於網際網路檔案館)
- PHP Functors - Function Objects in PHP
- What the heck is a functionoid, and why would I use one? (C++ FAQ)