簡體   English   中英

現代c ++替代函數指針

[英]modern c++ alternative to function pointers

到目前為止,我一直在使用函數指針,就像c ++中的這種格式一樣。 我偶爾會有一些用途,我想知道在c ++ 11/14中還有其他什么可以作為替代方案。

#include <iostream>
using namespace std;

void sayHello();
void someFunction(void f());

int main() {

    someFunction(sayHello);
    return 0;
}
void sayHello(){
    std::cout<<"\n Hello World";
}
void someFunction(void f()){
    f();
} 

我確實看過這個問題,但是無法理解任何優於傳統使用函數指針的優點。 另外我想問一下,使用函數指針有什么不對(不推薦)的事情因為我從未見過有人使用它們。 或任何其他替代禮物。

你提到的問題建議使用std :: function,但是當與std :: bind結合使用時,它並沒有強調(或根本沒有提及)它的值。

你的例子是最簡單的,但假設你有一個

std::function<void (int, int)> f ;

函數指針可以或多或少地執行相同的操作。 但是假設你需要一個函數g(int),它是f,第二個參數綁定為0.使用函數指針你不能做太多,使用std :: function你可以這樣做:

std::function<void(int)> g = std::bind(f, _1, 0) ;

作為傳統函數指針的替代,C ++ 11引入了模板別名 ,它結合了可變參數模板可以簡化函數指針sintax。 下面,如何創建“模板”函數指針的示例:

template <typename R, typename ...ARGS> using function = R(*)(ARGS...);

它可以這樣使用:

void foo()                { ... }
int bar(int)              { ... }
double baz(double, float) { ... }

int main()
{
    function<void>                  f1 = foo;
    function<int, int>              f2 = bar;
    function<double, double, float> f3 = baz;

    f1(); f2({}); f3({}, {});
    return 0;
}

此外,它可以巧妙地處理函數重載:

void overloaded(int)      { std::cout << "int version\n"; }
void overloaded(double)   { std::cout << "double version\n"; }

int main()
{
    function<void, int>    f4 = overloaded;
    function<void, double> f5 = overloaded;

    f4({}); // int version
    f5({}); // double version
    return 0;
}

並且可以用作聲明函數指針參數的相當簡潔的方法:

void callCallback(function<int, int> callback, int value)
{
    std::cout << "Calling\n";
    std::cout << "v: " << callback(value) << '\n';
    std::cout << "Called\n";
}

int main()
{
    function<int, int> f2 = bar;
    callCallback(f2, {});
    return 0;
}

這個模板別名可以用作std::function的替代品,它沒有缺點也沒有優點( 這里有很好的解釋 )。

現場演示

簡而言之,我認為模板別名與可變參數模板相結合是一個很好的,漂亮的,現代的C ++替代原始函數指針(這個別名畢竟仍然是函數指針)但是std::function很好,很好,很整潔,現代C ++以及具有良好優勢的考慮因素。 堅持使用函數指針(或別名)或選擇std::function取決於您的實現需求。

我確實看過這個問題,但是無法理解任何優於傳統使用函數指針的優點。 另外我想問一下,使用函數指針有什么不對(不推薦)的事情因為我從未見過有人使用它們。

  • 正常的“全局”函數通常不具有/不具有狀態。 雖然在函數式編程范式中遍歷狀態並不一定有好處,但有時當狀態與已經改變的東西正交時(例如,啟發式),狀態可能會派上用場。 仿函數(或函數對象)具有優勢。

  • 普通函數組合得不是很好(創建較低級函數的更高級函數)。

  • 正常功能不允許動態綁定其他參數。

  • 有時,正常功能可以替代lambda,反之亦然,具體取決於具體情況。 通常,人們不會因為在“容器遍歷”期間有一些非常本地/特定的要求而想要編寫特殊功能。

另外我想問一下,使用函數指針有什么不對(不推薦)的事情因為我從未見過有人使用它們。

是的 函數指針是可怕的,可怕的東西。 首先,它們不支持通用 - 所以你不能采用一個函數指針,比如說,對任何T需要std::vector<T> 其次,他們不支持有約束力的國家,所以如果在將來的任何時候,任何人都希望引用其他國家,他們就完全搞砸了。 這是特別糟糕,因為這包括this成員函數。

在C ++ 11中使用函數有兩種方法。 首先是使用模板。 第二種是使用std :: function。

模板有點像這樣:

template<typename T> void func(F f) {
    f();
}

這里的主要優點是它接受任何類型的函數對象,包括函數指針,lambda,functor,bind-result等等,並且F可以具有任意數量的函數調用重載,包括任何簽名,包括模板,它可以有任何任何綁定狀態的大小。 所以它超級靈活。 它也是最高效的,因為編譯器可以內聯運算符並直接在對象中傳遞狀態。

int main() {
    int x = 5;
    func([=] { std::cout << x; });
}

這里的主要缺點是模板的通常缺點 - 它不適用於虛函數,必須在標題中定義。

另一種方法是std::function std::function具有許多相同的優點 - 它可以是任何大小,綁定到任何狀態,並且可以調用任何東西,但交易一兩個。 主要是,簽名在類型定義時固定,因此對於某些尚未知的T ,你不能有std::function<void(std::vector<T>)> ,也可能有涉及一些動態間接/分配(如果你不能SBO)。 這樣做的好處是,由於std::function是一個真正的具體類型,你可以像任何其他對象一樣傳遞它,因此它可以用作虛函數參數等等。

基本上,函數指針只是非常有限,並不能真正任何有趣的事情,並使API非常不靈活。 他們令人討厭的語法在海洋中是一種小便,用模板別名減少它是搞笑但沒有意義的。

暫無
暫無

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

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