Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Tutorial(指南)

Basic Usage(基本用法)
Free functions(自由函數)
Member functions(成員函數)
References to Function Objects(引向函數對象的引用)
Comparing Boost.Function function objects(比較 Boost.Function 函數對像)

Boost.Function 有兩種語法形式:首選形式和兼容形式。首選形式更接近於 C++ 語言,並減少了需要被考慮的獨立的模板參數的個數,通常會改進可讀性,但是,由於編譯器的 bug 首選形式並不被所有的平台支持。兼容性是可以工作在所有被 Boost.Function 支持的編譯器上。參考下面的表格以確定在你的編譯器上使用哪種語法形式。

首選語法 兼容語法
  • GNU C++ 2.95.x, 3.0.x, 3.1.x
  • Comeau C++ 4.2.45.2
  • SGI MIPSpro 7.3.0
  • Intel C++ 5.0, 6.0
  • Compaq's cxx 6.2
  • Microsoft Visual C++ 7.1
  • 支持首選語法的任何編譯器
  • Microsoft Visual C++ 6.0, 7.0
  • Borland C++ 5.5.1
  • Sun WorkShop 6 update 2 C++ 5.3
  • Metrowerks CodeWarrior 8.1

如果你的編譯器沒有出現在這個列表中,請試用首選語法並向 Boost 郵件列表報告你的結果,以便我們可以保持這個表格的最新狀態。

Basic Usage(基本用法)

一個函數包裝類可以簡單地通過用想要的返回類型和參數類型來實例化 function 類模板來定義,簡稱為 C++ 函數類型。任何個數的參數都可以提供,直到某個實現定義的上限(10 是缺省的最大值)。下面就是聲明一個 function object wrapper(函數對像包裝類)f,它持有兩個 int 參數並返回一個 float

首選語法 兼容語法
boost::function<float (int x, int y)> f;
boost::function2<float, int, int> f;

缺省情況下,函數對像包裝類是空的,所以我們創建一個函數對像賦給 f

struct int_div { 
  float operator()(int x, int y) const { return ((float)x)/y; }; 
};

f = int_div();

現在我們可以用 f 來執行底層的函數對像 int_div

std::cout << f(5, 3) << std::endl;

我們可以自由地賦任何函數對像給 f。如果 int_div 被定義為持有兩個 long 操作數,隱式轉換會在沒有任何用戶干預的情況下應用於參數。對於參數類型的僅有的限制是它們是可拷貝構造的,所以我們甚至可以用引用或數組:

首選語法
boost::function<void (int values[], int n, int& sum, float& avg)> sum_avg;

兼容語法
boost::function4<void, int*, int, int&, float&> sum_avg;

void do_sum_avg(int values[], int n, int& sum, float& avg)
{
  sum = 0;
  for (int i = 0; i < n; i++)
    sum += values[i];
  avg = (float)sum / n;
}

sum_avg = &do_sum_avg;

調用一個實際上沒有包含函數對象的函數對像包裝類是一個 precondition violation(前提違例),很像試圖用一個空的函數指針調用函數,並拋出一個 bad_function_call 異常。我們可以通過在一個布爾上下文中使用它(如果包裝類不為空,將求值為 true)或將它和 0 作比較來檢查空函數對像包裝類。例如:

if (f)
  std::cout << f(5, 3) << std::endl;
else
  std::cout << "f has no target, so it is unsafe to call" << std::endl;

另一個可選方法是,empty() 方法可以返回這個包裝類是否為空。

最後,我們可以通過為它賦值為 0 或調用 clear() 成員函數來清空一個函數目標,例如,

f = 0;

Free functions(自由函數)

自由函數指針被認為是帶有 const 函數調用操作符的單例函數對象,並因此可以直接用於函數對像包裝類:

float mul_ints(int x, int y) { return ((float)x) * y; }

f = &mul_ints;

注意,& 並不是真的必要,除非你使用 Microsoft Visual C++ 版本 6。

Member functions(成員函數)

在很多系統中,回調通常是對一個特定對象的成員函數的調用。這通常被認為是「參數綁定」,而且已經超出 Boost.Function 的範疇。無論如何,直接調用成員函數是被支持的,所以下面的代碼是合法的:

struct X {
  int foo(int);
};

首選語法 兼容語法
boost::function<int (X*, int)> f;

f = &X::foo;
  
X x;
f(&x, 5);
boost::function2<int, X*, int> f;

f = &X::foo;
  
X x;
f(&x, 5);

有幾個支持參數綁定的庫已經存在。下面概述三個這樣的庫:

  • Bind。這個庫允許任何函數對象的參數綁定。它是輕量級的而且可移植性好。

  • C++ 標準庫。將 std::bind1ststd::mem_fun 合在一起使用,可以將一個指向成員函數的指針的對象綁定到 Boost.Function:

    首選語法 兼容語法
      boost::function<int (int)> f;
    X x;
    f = std::bind1st(
          std::mem_fun(&X::foo), &x);
    f(5); // Call x.foo(5)
      boost::function1<int, int> f;
    X x;
    f = std::bind1st(
          std::mem_fun(&X::foo), &x);
    f(5); // Call x.foo(5)

  • Lambda 庫。這個庫提供一個強大的合成機制,利用非常自然的 C++ 語法去構造函數對象。lambda 需要一個相當符合 C++ 標準的編譯器。

References to Function Objects(引向函數對象的引用)

在某些情況下,讓Boost.Function 克隆一個函數對像需要付出高昂的代價(或者是語義錯誤的)。在這樣的情況下,要求 Boost.Function 只保留引向實際的函數對象的引用是有可能的。這可以通過使用 refcref 函數去包裝一個引向函數對象的引用來做到:

首選語法 兼容語法
stateful_type a_function_object;
boost::function<int (int)> f;
f = boost::ref(a_function_object);

boost::function<int (int)> f2(f);
stateful_type a_function_object;
boost::function1<int, int> f;
f = boost::ref(a_function_object);

boost::function1<int, int> f2(f);

這裡,f 不會生成 a_function_object 的一個拷貝,當 f2f 的引向 a_function_object 的引用為目標時,也不會生成這個拷貝。另外,當使用引向函數對象的引用時,Boost.Function 在賦值和構造過程中不會拋出異常。

Comparing Boost.Function function objects(比較 Boost.Function 函數對像)

函數對像包裝類可以通過 ==!= 與任何能夠存儲在這個包裝類內的函數對像進行比較。如果這個函數對像包裝類包含一個某種類型的函數對象,它將和給定的函數對像(這個函數對像必須是 EqualityComparable 的,而且必須有一個 boost::function_equal 的重載)進行比較。例如:

int compute_with_X(X*, int);

f = &X::foo;
assert(f == &X::foo);
assert(&compute_with_X != f);

當和一個 reference_wrapper 的實例進行比較時,reference_wrapper 中的對象的地址和函數對像包裝類中存儲的對象的地址進行比較:

a_stateful_object so1, so2;
f = boost::ref(so1);
assert(f == boost::ref(so1));
assert(f == so1); // Only if a_stateful_object is EqualityComparable
assert(f != boost::ref(so2));

Last revised: November 03, 2006 at 19:41:10 GMT

Copyright 2001-2004 Douglas Gregor

PrevUpHomeNext