boost.png (6897 bytes)

mem_fn.hpp

 

目錄

目的

常見問題

mem_fn 可以用來替代標準 std::mem_fun[_ref] 適配器嗎?

在已存在代碼中,我應該用 mem_fn 替換 std::mem_fun[_ref] 的每一次出現嗎?

mem_fn 可以和 COM 方法一起工作嗎?

為什麼 BOOST_MEM_FN_ENABLE_STDCALL 不被自動定義?

接口

概要

共通需求

get_pointer

mem_fn

實現

文件

相關內容

參數數量

"__stdcall", "__cdecl" 和 "__fastcall" 支持

感謝

Purpose(目的)

boost::mem_fn 是標準函數 std::mem_funstd::mem_fun_ref 的泛化。它支持帶有多個參數的成員函數指針,並且返回的函數對象可以持有一個對像實例的指針,引用或者智能指針作為它的第一個參數。mem_fn 也支持指向數據成員的指針,它把它們看作不持有參數且返回一個成員的(常)引用的函數。

mem_fn 的目的分成兩個部分。首先,它允許用戶以熟悉的

    std::for_each(v.begin(), v.end(), boost::mem_fn(&Shape::draw));

語法在一個容器上調用一個成員函數,即使這個容器存儲的是智能指針。

第二,它可以被想要將一個成員函數指針看做一個函數對象的庫開發者當做一個構件來使用。一個庫可以通過以下這種形式的重載定義一個增強的 for_each 算法:

template<class It, class R, class T> void for_each(It first, It last, R (T::*pmf) ())
{
std::for_each(first, last, boost::mem_fn(pmf));
}

它將接受很方便的語法:

    for_each(v.begin(), v.end(), &Shape::draw);

如果要文檔化這個特性,庫作者只需要簡單地記述:

template<class It, class R, class T> void for_each(It first, It last, R (T::*pmf) ());

效果:等價於 std::for_each(first, last, boost::mem_fn(pmf));

boost::mem_fn 可以鏈接到本頁。參見 bind 文檔中的例子。

mem_fn 持有一個參數,一個指向成員的指針,並返回一個適用於標準或用戶定義算法的函數對像:

struct X
{
void f();
};

void g(std::vector<X> & v)
{
std::for_each(v.begin(), v.end(), boost::mem_fn(&X::f));
};

void h(std::vector<X *> const & v)
{
std::for_each(v.begin(), v.end(), boost::mem_fn(&X::f));
};

void k(std::vector<boost::shared_ptr<X> > const & v)
{
std::for_each(v.begin(), v.end(), boost::mem_fn(&X::f));
};

返回的函數對像和輸入的成員函數持有同樣的參數,外加一個代表對像實例的「固定」的第一個參數。

當函數對像以 x 為第一個參數被調用,這個 x 既不是一個指向適當類(上例中的 X)的指針,也不是引向適當類(上例中的 X)的引用,它用 get_pointer(x)x 獲得一個指針。庫作者可以通過提供一個適當的 get_pointer 重載來「登記」他們的智能指針類,允許 mem_fn 識別並支持它們。

【注意:get_pointer 並沒有被限制於返回一個指針。它可以返回能用於一個成員函數調用表達式 (x->*pmf)(...) 中的任何對象。】

【注意:這個庫使用了一個 get_pointer 的未加限定的調用。因此,通過 argument-dependent lookup(參數依賴查找)它會發現除了一些 boost::get_pointer 重載之外,還有和對應的智能指針類定義在同一個名字空間中的 get_pointer 重載。】

所有由 mem_fn 返回的函數對象都會暴露一個 result_type typedef,它代表這個成員函數的返回類型。對於數據成員,result_type 定義為這個成員的類型。

Frequently Asked Questions(常見問題)

Can mem_fn be used instead of the standard std::mem_fun[_ref] adaptors?(mem_fn 可以用來替代標準 std::mem_fun[_ref] 適配器嗎?)

是的。對於簡單應用,mem_fn 提供了標準適配器沒有的額外功能。出標準適配器以外還使用了 std::bind1ststd::bind2ndBoost.Compose 的複雜表達式能夠使用自動利用 mem_fnboost::bind 來重寫。

Should I replace every occurence of std::mem_fun[_ref] with mem_fn in my existing code?(在已存在代碼中,我應該用 mem_fn 替換 std::mem_fun[_ref] 的每一次出現嗎?)

不。除非你有更好的理由這樣做。mem_fn 並非 100% 兼容標準適配器,雖然它更加優美。特別是,mem_fn 不返回 std::[const_]mem_fun[1][_ref]_t 類型的對象,而標準適配器會,而且使用標準 argument_typefirst_argument_type 內嵌的 typedefs 完全記述第一個參數的類型是不可能的。庫需要可適配的函數對象是為了讓函數可以不需要 mem_fn

Does mem_fn work with COM methods?(mem_fn 可以和 COM 方法一起工作嗎?)

可以。只需要 #define BOOST_MEM_FN_ENABLE_STDCALL

Why isn't BOOST_MEM_FN_ENABLE_STDCALL defined automatically?(為什麼 BOOST_MEM_FN_ENABLE_STDCALL 不被自動定義?)

一般而言,不可移植擴展在默認狀態下應該關閉,以防止廠家鎖定。如果 BOOST_MEM_FN_ENABLE_STDCALL 被自動定義,你可能無意中使用了它而並不明確你的代碼是否需要可移植。另外,缺省的調用約定就是 __stdcall 是有可能的,在這種情況下,啟用 __stdcall 支持會導致重複定義。

Interface(接口)

Synopsis(概要)

namespace boost
{

template<class T> T * get_pointer(T * p);

template<class R, class T> unspecified-1 mem_fn(R (T::*pmf) ());

template<class R, class T> unspecified-2 mem_fn(R (T::*pmf) () const);

template<class R, class T> unspecified-2-1 mem_fn(R T::*pm);

template<class R, class T, class A1> unspecified-3 mem_fn(R (T::*pmf) (A1));

template<class R, class T, class A1> unspecified-4 mem_fn(R (T::*pmf) (A1) const);

template<class R, class T, class A1, class A2> unspecified-5 mem_fn(R (T::*pmf) (A1, A2));

template<class R, class T, class A1, class A2> unspecified-6 mem_fn(R (T::*pmf) (A1, A2) const);

// implementation defined number of additional overloads for more arguments

}

Common requirements(共通需求)

概要中涉及的所有 unspecified-N 類型都是 CopyConstructible(可拷貝構造)的和 Assignable(可賦值)的。它們的拷貝構造函數和賦值操作符不拋出異常。unspecified-N::result_type 被定義為作為一個參數傳遞給 mem_fn 的成員函數指針的返回值(概要中的 R)。unspecified-2-1::result_type 被定義為 R

get_pointer

template<class T> T * get_pointer(T * p)

返回:p

拋出:不拋出異常。

mem_fn

template<class R, class T> unspecified-1 mem_fn(R (T::*pmf) ())

返回:一個函數對像 f,當 t 是一個類型 T 或其派生類型的左值時,使得表達式 f(t) 等價於 (t.*pmf)(),否則,等價於 (get_pointer(t)->*pmf)()

拋出:不拋出異常。

template<class R, class T> unspecified-2 mem_fn(R (T::*pmf) () const)

返回:一個函數對像 f,當 t 的類型是 T [const] 或其派生類型時,使得表達式 f(t) 等價於 (t.*pmf)(),否則,等價於 (get_pointer(t)->*pmf)()

拋出:不拋出異常。

template<class R, class T> unspecified-2-1 mem_fn(R T::*pm)

返回:一個函數對像 f,當 t 的類型是 T [const] 或其派生類型時,使得表達式 f(t) 等價於 t.*pm,否則,等價於 get_pointer(t)->*pm

拋出:不拋出異常。

template<class R, class T, class A1> unspecified-3 mem_fn(R (T::*pmf) (A1))

返回:一個函數對像 f,當 t 是一個類型 T 或其派生類型的左值時,使得表達式 f(t, a1) 等價於 (t.*pmf)(a1),否則,等價於 (get_pointer(t)->*pmf)(a1)

拋出:不拋出異常。

template<class R, class T, class A1> unspecified-4 mem_fn(R (T::*pmf) (A1) const)

返回:一個函數對像 f,當 t 的類型是 T [const] 或其派生類型時,使得表達式 f(t, a1) 等價於 (t.*pmf)(a1),否則,等價於 (get_pointer(t)->*pmf)(a1)

拋出:不拋出異常。

template<class R, class T, class A1, class A2> unspecified-5 mem_fn(R (T::*pmf) (A1, A2))

返回:一個函數對像 f,當 t 是一個類型 T 或其派生類型的左值時,使得表達式 f(t, a1, a2) 等價於 (t.*pmf)(a1, a2),否則,等價於 (get_pointer(t)->*pmf)(a1, a2)

拋出:不拋出異常。

template<class R, class T, class A1, class A2> unspecified-6 mem_fn(R (T::*pmf) (A1, A2) const)

返回:一個函數對像 f,當 t 的類型是 T [const] 或其派生類型時,使得表達式 f(t, a1, a2) 等價於 (t.*pmf)(a1, a2),否則,等價於 (get_pointer(t)->*pmf)(a1, a2)

拋出:不拋出異常。

Implementation(實現)

Files(文件)

Dependencies(相關內容)

Number of Arguments(參數個數)

實現支持最多 8 個參數的函數對象。這不是設計的固有限制,只是一個實現細節。

"__stdcall", "__cdecl" and "__fastcall" Support

有些平台允許幾種 calling convention(調用約定——函數被調用時的規則:參數如何傳遞,返回值如何處理,誰來清理棧(如果有的話))分屬不同類型的(成員)函數。

例如,Windows API 函數和 COM 接口成員函數使用一種名為 __stdcall 的調用約定。Borland VCL 組件使用 __fastcall。UDK,OpenOffice.org 的組件模型,使用 __cdecl

為了和 __stdcall 成員函數一起使用 mem_fn,在直接或間接包含 <boost/mem_fn.hpp> 之前 #defineBOOST_MEM_FN_ENABLE_STDCALL

為了和 __fastcall 成員函數一起使用 mem_fn,在直接或間接包含 <boost/mem_fn.hpp> 之前 #defineBOOST_MEM_FN_ENABLE_FASTCALL

為了和 __cdecl 成員函數一起使用 mem_fn,在直接或間接包含 <boost/mem_fn.hpp> 之前 #defineBOOST_MEM_FN_ENABLE_CDECL

最好在項目選項中定義這些宏,在命令行上使用 –D,或作為使用了 mem_fn 的翻譯單元(.cpp 文件)的第一行。不遵守這個規則,當一個包含 mem_fn.hpp 的頭文件在這些宏定義之前,可能會導致隱蔽的錯誤。

【注意:這是一個不可移植擴展。它不是接口的一部分。】

【注意:有些編譯器只對 __stdcall 關鍵字提供最小的支持。】

Acknowledgements(感謝)

Rene Jager 的最初的關於用 traits 類使 mem_fn 適合用戶定義智能指針的建議激發了基於 get_pointer 設計的靈感。

正式 review 期間,Richard Crossley,Jens Maurer,Ed Brey 和其他人提出大量改進建議。review 主管者是 Darin Adler。

Steve Anichini 指出 COM 接口使用 __stdcall

Dave Abrahams 改良了 bindmem_fn 以支持在不完善編譯器上的空返回。

Daniel Boelzle 指出 UDK 使用 __cdecl

Copyright c 2001, 2002 by Peter Dimov and Multi Media Ltd. Copyright 2003-2005 Peter Dimov. Distributed under the Boost Software License, Version 1.0. See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.