2013-03-10 112 views
1

可以使用boost :: function和/或boost :: bind來簡化/改進以下函數指針傳遞嗎?通過boost :: function和/或boost :: bind來傳遞函數指針參數

void PassPtr(int (*pt2Func)(float, std::string, std::string)) 
{ 
    int result = (*pt2Func)(12, "a", "b"); // call using function pointer 
    cout << result << endl; 
} 

// execute example code 
void Pass_A_Function_Pointer() 
{ 
    PassPtr(&DoIt); 
} 
+1

這取決於你正在尋找什麼樣的答案!當然,以上所有內容都可以簡化爲'cout << DoIt(12,「a」,「b」)<< endl;',但我想這不是你想要的。也就是說,在這裏沒有明顯的機會利用Boost特性,因爲你調用的是純函數指針,而不是函數對象等。 – 2013-03-10 14:30:32

+0

它可以被改進,然後你可以使用任何成員函數或lambda表達式(如果你有C++ 11兼容編譯器),不僅是普通函數或靜態成員函數。當然,使用'boost :: bind'(或['std :: bind'](http://en.cppreference.com/w/cpp/utility/functional/bind)),你可以「綁定」任何數字在傳遞函數對象之前的參數。 – 2013-03-10 14:31:05

+0

什麼是固定的,什麼可以改變?如果'PassPtr'和'DoIt'的簽名是固定的,那麼否,代碼就像它得到的那樣簡單。 – 2013-03-10 14:32:13

回答

4

您可以使用boost::function<>使用不同類型的可調用的對象作爲函數的輸入,使之成爲可能。

以下是使用C++ 11的示例(請參閱本示例之後的註釋)。這是你將如何改寫你的函數:

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

void PassFxn(std::function<int(float, std::string, std::string)> func) 
//   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
{ 
    int result = func(12, "a", "b"); // call using function object 
    std::cout << result << std::endl; 
} 

這是一對夫婦的功能來測試它:

int DoIt(float f, std::string s1, std::string s2) 
{ 
    std::cout << f << ", " << s1 << ", " << s2 << std::endl; 
    return 0; 
} 

int DoItWithFourArgs(float f, std::string s1, std::string s2, bool b) 
{ 
    std::cout << f << ", " << s1 << ", " << s2 << ", " << b << std::endl; 
    return 0; 
} 

struct X 
{ 
    int MemberDoIt(float f, std::string s1, std::string s2) 
    { 
     std::cout << "Member: " << f << ", " << s1 << ", " << s2 << std::endl; 
     return 0; 
    } 

    static int StaticMemberDoIt(float f, std::string s1, std::string s2) 
    { 
     std::cout << "Static: " << f << ", " << s1 << ", " << s2 << std::endl; 
     return 0; 
    } 
}; 

這裏是測試程序:

int main() 
{ 
    PassFxn(DoIt); // Pass a function pointer... 

    // But we're not limited to function pointers with std::function<>... 

    auto lambda = [] (float, std::string, std::string) -> int 
    { 
     std::cout << "Hiho!" << std::endl; 
     return 42; 
    }; 

    PassFxn(lambda); // Pass a lambda... 

    using namespace std::placeholders; 
    PassFxn(std::bind(DoItWithFourArgs, _1, _2, _3, true)); // Pass bound fxn 

    X x; 
    PassFxn(std::bind(&X::MemberDoIt, x, _1, _2, _3)); // Use a member function! 

    // Or, if you have a *static* member function... 
    PassFxn(&X::StaticMemberDoIt); 

    // ...and you can basically pass any callable object! 
} 

這裏是一個live example

備註

您可以輕鬆更改std::function<>boost::function<>std::bind<>boost::bind<>如果您正在使用C++ 03的工作(其實來自Boost.Function是什麼啓發了std::function<>後來成爲標準的一部分C++庫)。在這種情況下,不必包含<functional>標題,而必須包含boost/function.hppboost/bind.hpp標題(只有在您想使用boost::bind時才使用後者)。

有關其他示例,應該給您一個感受std::function<>/boost::function<>通過其封裝任何類型的可調用對象的能力,也請參閱this Q&A on StackOverflow

+0

太好了!在我標記爲已回答之前,您能否再添加一個示例?當DoIt是傳遞成員函數時,語法如何查找? – pingu 2013-03-10 14:55:08

+0

@pingu:你走了,更新:) – 2013-03-10 14:57:32

+0

真棒!謝謝 – pingu 2013-03-10 15:00:14

3

我假設您想要改進PassPtr的功能,而不是您提供的所有示例代碼。如果您正在使用C++ 11,並且可以使用lambda表達式,我將簡化它只是:

template <typename Func> 
void PassPtr(Func f) { 
    std::cout << f(12, "a", "b") << std::endl; 
} 

這將允許任何調用對象爲f傳遞。通過推導出的模板類型來獲取函數的原因是爲了允許傳遞的任何lambda表達式被內聯。當然,這不會對傳遞的函數執行任何特定的簽名(或者它甚至應該是可調用的對象)。例如,如果你通過一個int,你會得到一些令人困惑的編譯器錯誤。

另一種方法,使用[boost|std]::function,就是要做到這一點:

void PassPtr(std::function<int(float, std::string, std::string)> f) { 
    std::cout << f(12, "a", "b") << std::endl; 
} 

這將允許任何類型的可調用對象的傳遞,正如上述,但可能不會導致被內聯lambda表達式。