2012-12-10 56 views
2

我想使用boost :: call_once()來實現線程安全的lazy-construction singleton場景,但是,基礎singleton類有許多派生類因此getInstance()函數接受一個參數來確定要初始化哪個派生類。代碼如下,如何在帶參數的函數上使用boost :: call_once()

Singleton * Singleton::getInstance(Input * a) { 
if (!instance) { 
    instance = buildme(a); //buildme() will return a derived class type based on input a. 
    } 
return instance; 
} 

我想用boost::call_once(),但看起來它只能在功能不帶參數void (*func)()使用。如果有人知道另一種解決方案,請幫忙。

謝謝。

編輯::

另一個問題是,如何調用使用call_once非靜態成員函數?我有一個非靜態的init()這個類的成員函數,但我找不到使用boost::call_once()調用它的正確語法。或者我應該使init()和它使用的一切都是靜態的?

謝謝。

回答

7

您可以使用boost::bind將其他函數參數綁定到函子對象。就像這樣:

Input* input = ???; 
boost::call_once(flag, boost::bind(&Singleton::getInstance, input)); 

您可以使用boost::bind調用非靜態成員函數中,通過傳遞要函數調用boost::bind類的實例。

class Foo 
{ 
public: 
    void func(int) { /* do something */} 
}; 

Foo f; 
boost::call_once(flag, boost::bind(&foo::func, &f, 10)); 

用C++ 11,可以使用std::bind,這裏是另一個例子。 boost::bind非常相似。

#include <utility> 
#include <functional> 
#include <iostream> 
#include <string> 

void f(int x) 
{ 
    std::cout << "f(" << x << ")\n"; 
} 

void g(int x, const std::string& y) 
{ 
    std::cout << "g(" << x << ", " << y << ")\n"; 
} 


int main() 
{ 
    auto ten = std::bind(&f, 10); 
    auto example = std::bind(&g, 20, "Twenty"); 

    ten(); 
    example(); 

    return 0; 
} 
+3

實際上的std :: call_once的在C++ 11接受任何數量的參數,其是完全轉發到可調用所以不需要用於這種情況下的std ::綁定(一次標誌和可調用之後)。 – John5342

+0

謝謝你們兩位。乍得的例子是非常有用的,現在我知道綁定的用法。還要感謝@ John5342讓我知道這些有用的信息。 – Derek

+0

@ John5342應該是一個答案。會提高它。 – Walter

7

C++ 11包含call_once的實現(受相當於Boost.Threads設施的啓發)。它使用可變參數模板和完美的轉發來獲取任意數量的參數。

#include <mutex> 
#include <string> 

void only_called_once(int i, std::string const & str) { 
    // We only get here once.                                       
} 

void call_free() { 
    static std::once_flag once; 
    std::call_once(once, only_called_once, 42, "The answer"); 
} 

可以可調用後傳遞的參數的任意數量和它們將被完全轉發(包括r值/ L值,常量,易失性,等)。

這也適用於成員函數。作爲可調用對象之後的第一個參數,您只需傳遞一個指向對象的指針(可轉換爲成員函數所屬的類型)。

struct bar { 
public: 
    void only_call_once(int i, std::string const & str); 
}; 

void call_member() { 
    static std::once_flag once; 
    bar instance; 
    std::call_once(once, &bar::only_call_once, &instance, 42, "The answer"); 
} 

如果你被卡住加速,那麼你可以使用boost::bind爲同一目的,已經在另一個答案解釋。通過將成員函數指針和實例作爲以下參數傳遞,使用boost::bind的成員函數的工作方式與上述相同。

+0

+1承諾。 – Walter

相關問題