簡體   English   中英

在 C++ 中將函數作為參數傳遞

[英]Passing functions as arguments in C++

我對 C++ 有點生疏,在使用了一年的 python 后我要切換了。 自然地,我想將來自 python 的懶惰轉化為 C++。

我剛剛發現了 rot13,我對此感到非常興奮。 我找到了 3 種方法,我想做一些性能測試。 我還想看看在原地修改字符串或創建一個新字符串是否有區別。 所以我最終得到了 6 個函數。

在第一種方法中,我使用 std::map 來映射字符,因此我構建了一個初始化映射的類,在第二種方法中我使用了三元運算符,第三種我使用了位移。

現在函數原型看起來像這樣

// map dependent
void Rot13::convert_inplace(string& mystr){

string Rot13::convert(const string& mystr){

// ternary operator
void bitrot_inplace(string& mystr){

string bitrot(const string&  mystr){

// bit shift
void bitshiftrot_inplace(string& mystr){

string bitshiftrot(const string& mystr){

我想構建一個接受這些函數作為參數的函數,然后計算時間並打印結果

所以我查看了 stackoverflow, 1 , 2 ,然后我想出了這個

typedef void (*vfc)(string str);

void printtime_inplace(string title, vfc func){

我嘗試了這種構造,但這意味着我受到vfc返回類型的限制,在我的情況下它是voidstring ,並且我需要傳遞類的指針。 因此,我將不得不做 3 個函數來適應不同的函數,即類成員函數的函數、void 返回類型的函數和字符串返回類型的函數。

於是我問自己,我真的需要使用模板來不寫3次相同的函數嗎? 我真的對模板沒有信心,但我應該做 3 個typedefs並構造 printtime 函數以接受模板嗎? 此外,有沒有辦法告訴模板您將只接受這些類型(即我定義的類型)?

另一個問題,這是一個好的設計嗎? 或者你會建議其他設計嗎? 另一個實現?

IMO,最簡單的方法是使用模板而不是嘗試編寫具有具體類型的函數。

template<typename Function>
void printtime_inplace(string title, Function func)
{
    //...
    func(title);
    //...
}

這現在將允許您采取任何“功能”。 您可以向它傳遞一個常規函數、一個函子、一個 lambda、一個std::function ,基本上,任何可調用的。 編譯器將為您消除不同的實例化,但就您的代碼而言,您正在調用相同的函數。

您可以使用std::function來提供這樣的模板:

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

void convert_inplace(std::string& mystr){}
std::string convert(const std::string& mystr){
    return mystr;
}
void bitrot_inplace(std::string& mystr){}

template<typename ret, typename par>
using fn = std::function<ret(par)>;

template<typename ret, typename par>
void caller(fn<ret,par> f) {
    typename std::remove_reference<par>::type p;
    ret r = f(p);
}

template<typename par>
void caller(fn<void,par> f) {
    typename std::remove_reference<par>::type p;
    f(p);
}

int main() {
    auto f1 = fn<void,std::string&>(convert_inplace);
    auto f2 = fn<std::string,const std::string&>(convert);
    auto f3 = fn<void,std::string&>(bitrot_inplace);
    caller(f1);
    caller(f2);
    caller(f3);
    return 0;
}

請參閱現場演示

如果你想要一個帶有可變參數的函數,這里有一個基於 user0042s 答案的例子(另見https://github.com/goblinhack/c-plus-plus-examples/blob/master/std_function_with_variadic_template/README.md )

#include <iostream>

int my_wrapped_function (int x, const std::string y)
{
    std::cout << "SUCCESS: Hello from my_wrapped_function(x=" << x << ", y=" << y << ");" << std::endl;
    return 43;
}

void my_argument_modifier (int &x)
{
    std::cout << "SUCCESS: Hello from my_argument_modifier(x=" << x << ") => " << x + 1 << ";" << std::endl;
    x++;
}

template<typename ret, typename T, typename... Rest>
using fn = std::function<ret(T, Rest...)>;

template<typename ret, typename T, typename... Rest>
ret wrapper(fn<ret, T, Rest...> f, T t, Rest... rest)
{
    return f(t, rest...);
}

template<typename ret, typename T, typename... Rest>
ret wrapper(fn<ret, T&, Rest&...> f, T& t, Rest&... rest)
{
    return f(t, rest...);
}

int main()
{
    // Wrap a function with variable arguments
    auto f1 = fn<int,int,const std::string>(my_wrapped_function);
    auto result = wrapper(f1, 42, std::string("hello"));
    // Result should be 43: 

    // Wrap a function that modifies its arguments
    auto f2 = fn<void,int&>(my_argument_modifier);
    wrapper(f2, result);
    // Result should be 44: 

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM