2009-08-25 47 views
6

我如何散列(std :: tr1 :: hash或boost :: hash)C++指針 - 成員函數?如何散列和比較指向成員函數的指針?

實施例:

我有幾個布爾(類:: * functionPointer)()(未靜態)該點到類類的幾個diferent方法和我需要散列那些指針到成員函數。

我該怎麼做?

另外我怎麼能比較(std :: less)這些成員函數指針,所以我可以將它們存儲在std :: set中?

+7

這是真的,通常沒有任何理由來散列指針,因爲它直接指向你想要訪問的東西。請提供一些說明你所問的內容的代碼。 – 2009-08-25 13:24:48

+0

你什麼時候可以說一個函數指針比另一個函數指針'少'? – 2009-08-25 13:30:27

+0

@bojan:如果比較的唯一目的是將它們存儲在排序列表中,則任何確定性排序都會執行。例如二進制值。 – erikkallen 2009-08-25 13:35:19

回答

13

所有C++對象(包括指向成員函數的指針)都在內存中表示爲一個字符數組。所以,你可以嘗試:

bool (Class::*fn_ptr)() = &Class::whatever; 
const char *ptrptr = static_cast<const char*>(static_cast<const void*>(&fn_ptr)); 

現在治療ptrptr爲指向的(sizeof(bool (Class::*)()))字節數組,哈希或比較這些字節。如果您願意,您可以使用unsigned char而不是char

這保證不會出現誤報 - 在C++ 03中,指向成員函數的指針是POD,這意味着可以使用memcpy複製它們。這意味着如果具有相同的逐字節值,則它們是相同的。

問題是成員函數指針的存儲表示可能包含不參與值的位 - 所以它們對於指向同一成員函數的不同指針不一定相同。或者編譯器出於某種不明原因可能有不止一種方式指向同一個類的相同功能,這在字節上是不相等的。無論哪種方式,你可以得到錯誤的否定。您將不得不查看成員函數指針如何在您的實現中實際工作。它必須以某種方式爲成員函數指針實現operator==,並且如果能夠找出如何可以找出訂單和散列函數。

這可能很困難:成員函數指針很尷尬,根據指向哪種函數(虛擬,繼承),存儲可能包含不同數量的非參與「鬆散空間」。所以你可能不得不與編譯器的實現細節進行非常重要的交互。這篇文章可能會幫助你開始:http://www.codeproject.com/KB/cpp/FastDelegate.aspx

一個更清潔的替代方案可能是通過數組進行線性搜索,以便「規範化」所有函數指針,然後根據「規範」該數組中的函數指針的實例。取決於你的性能要求。即使有要求,類(及其派生類)是否具有如此多的函數以至於線性搜索需要很長時間?

typedef bool (Class::*func)(); 
vector<func> canon; 

size_t getIndexOf(func fn_ptr) { 
    vector<func>::iterator it = find(canon.begin(), canon.end(), fn_ptr); 
    if (it != canon.end()) return it - canon.begin(); 
    canon.push_back(func); 
    return canon.size() - 1; 
} 
+0

感謝char *做的竅門! 只有在我的編譯器中,我需要reinterpret_cast而不是static_cast。 – AllDayCpp 2009-08-25 14:57:27

+1

一些棘手問題的優秀處理,+1。我沒有想到pmf1 == pmf2並不一定意味着按位身份。 – 2009-08-25 14:58:57

+0

指向成員函數的指針可能包含填充,當比較相等時會被忽略,並且可能採用隨機值。散列任何填充字節將導致散列函數失敗。 – 2012-10-25 10:18:51

0

我不能投的指針(在Microsoft編譯器2010)在前面的回答描述,但這個工作對我來說:

static string fmptostr(int atype::*opt) 
    { 
     char buf[sizeof(opt)]; 
     memcpy(&buf,&opt,sizeof(opt)); 
     return string(buf,sizeof(opt)); 
    } 

關於指針的按位的身份,可以按位,因此似乎是否使用了合適的編譯器開關。至少對於Microsoft編譯器E.g 使用#pragma pointers_to_members 和switch .../vmg