2014-01-26 74 views
0

是否有可能以某種方式使函數(C++ 11),它將接受不同的參數取決於第一個? 比方說,我需要以下行爲:C++ 11函數參數

enum TypeFill{Solid, Gradient1, Gradient2}; 

void fill(const TypeFill t, Type1 param1 = NULL, Type2 param2 = NULL){ 
    if (t == Solid){ 
     fillSolid(param1); 
    } else if (t == Gradient1){ 
     fillGradient1(param1, param2); 
    } else if (t == Gradient2){ 
     fillGradient2(param1, param2); 
    } 
} 

private: 
fillSolid(Brush b){};     
fillGradient1(Color c1, Color c2){}; 
fillGradient2(Color c1, Color c2){}; 

調用示例:

fill(Solid, Brush(1.0, 0.0, 0.0)){};     
fill(Gradient1, Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0)){}; 
fill(Gradient2, Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0)){}; 

如果這可能只是懷疑。我覺得可能是一些可以做到與enable_if和模板特,但可能不...

+2

什麼是'枚舉TypeFill ;'?...和其他代碼中,我不知道你想要達到什麼目的。 – Nawaz

+0

因爲在編譯時需要知道填充類型,所以像這樣比'solidFill(Brush)','gradientFill(Color,Color)'等更好嗎?當然,有很多方法可以公開這樣的API;我只是選擇最明顯的簡單案例作爲參考。 – Jon

+0

@Nawaz:他們想根據第一個參數的值(這是不可能的,因此我們正在談論一些道德等價物)允許或不允許「fill」的不同簽名。 – Jon

回答

0

這裏的理智將是使用你直接使用的三個函數。如果你絕對必須有語法:

fill(Solid, Brush(1.0, 0.0, 0.0)); 
fill(Gradient1, Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0)); 
fill(Gradient2, Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0)); 

您可以從兩個重載得到它:

void fill(TypeFill t, Brush b) { 
    assert(t == Solid); 
    fillSolid(b); 
} 

void fill(TypeFill t, Color c1, Color c2) { 
    switch(t) { 
    case Gradient1: 
    fillGradient1(c1, c2); 
    break; 
    case Gradient2: 
    fillGradient2(c1, c2); 
    break; 
    default: 
    assert(false); 
    break; 
    } 
} 

,如果你想有一個單一的功能嚴重,足以與任何可能沿着扔掉類型安全調試錯誤,你可以使用C風格的可變參數:

void fill(TypeFill t, ...) { 
    va_list ap; 
    va_start(ap, t); 
    switch(t) { 
    case Gradient1: 
    fillGradient1(va_arg(ap, Color), va_arg(ap, Color)); 
    break; 
    case Gradient2: 
    fillGradient2(va_arg(ap, Color), va_arg(ap, Color)); 
    break; 
    case Solid: 
    fillSolid(va_arg(ap, Brush)); 
    break; 
    default: 
    assert(false); 
    break; 
    } 
    va_end(ap); 
} 

要小心,不要落入相抵觸的詳情見C++ 11§5.2.2/ 7 va_arg要求:

如果給定參數沒有參數,則參數以這樣一種方式傳遞,即接收函數可以通過調用va_arg(18.10)來獲取參數的值。在參數表達式上執行左值到右值(4.1),數組到指針(4.2)和函數到指針(4.3)的標準轉換。已經(可能是cv合格)類型std::nullptr_t的論據被轉換爲void*(4.10)。在這些轉換之後,如果參數沒有算術,枚舉,指針,成員指針或類類型,則該程序不合格。傳遞具有非平凡複製構造函數,非平凡移動構造函數或非平凡析構函數的類類型(第9章)的潛在評估參數,並且沒有相應的參數,它是由實現定義的語義有條件地支持的。如果參數具有整數或枚舉類型(受整型促銷(4.5)或受浮點促銷(4.6)支配的浮點類型),則在調用之前將參數的值轉換爲促銷類型。這些促銷被稱爲默認參數促銷

2

它歸結爲有幾個重載,所以最簡單的方法是定義:

  • fillSolid(Brush b)
  • fillGradient(Color c1, Color c2)

在本設計中你需要枚舉值在編譯時反正在每個特定的呼叫是已知的,所以沒有太多的收穫。

OTOH你可能會想重新設計你的代碼,這樣,而不是一個枚舉你有Fill有不同的實現實際的抽象像SolidGradient1Gradient2,等等,每一個都有自己的數據集。


後續:這是一個語法的例子,你可以使用模板得到:

fill<Solid>::call(Brush(1.0, 0.0, 0.0));    
fill<Gradient1>::call(Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0)); 
fill<Gradient2>::call(Color(1.0, 0.0, 0.0), Color(1.0, 1.0, 0.0)); 

枚舉現在是一個類模板參數,而不是一個函數的參數,所以它在解決編譯時和(成員)函數簽名能夠依賴它。

+1

提示:唯一的事情模板可以做的是代碼生成,而且你首先需要一個想法,真的很有趣的代碼生成 – Kos

+0

。 – tower120

+0

@Kos雖然技術上是的,但我不同意你的'唯一'部分。這裏期望的行爲實際上可以用簡單的模板專門化來實現,儘管我不認爲這適合於此。 – Paranaix