2014-08-31 61 views
1

我已經在Clojure(一種函數式語言)編程了一段時間,而且我必須使用C++作爲一個類。我一直在嘗試使用我在Clojure中享受過的一些功能(例如,高階函數,lambdas,參數線程,動態類型等),但我遇到了一些困難。如果函數參數內的語句;分支類型

你可以在Clojure中做的一件事(我假設其他函數式語言)幾乎在任何地方使用任何函數。例如,Clojure中的if語句可以插入到函數調用的參數/參數中,但在C++中,這是不可能的。

由於大的東西我做一個簡單的例子,我試圖讓下面的工作:

println(if (true) { 100 } else { 200 }); 

我實現的功能println接受任何數量的參數;它的工作方式與Clojure的println(與Java的System.out.println類似),但使用cout

顯然,if語句的語法可能是每個分支必須在後面有一個分號(禁止沒有括號的較短語法替代)。所以我添加了分號並將其放入函數println中,但這不起作用 - 編譯器拋出了一個expected expression錯誤。

所以我轉向宏。起初,我實現了這一點:

#define if1(pred, expr_true, expr_false) \ 
    if (pred) {       \ 
    return expr_true;     \ 
    } else {        \ 
    return expr_false;     \ 
    } 

,我把它放在println像這樣:

println(if1(true, 100, 200)); 

但導致該編譯器拋出了同樣的錯誤。

所以我想,也許我可以在一個lambda包裹if聲明(因爲在C++中,函數不能在函數調用的參數中聲明):

#define if2(pred, expr_true, expr_false) \ 
    []() -> decltype(auto){    \ 
    if (pred) { return expr_true; }  \ 
    else  { return expr_false; }}() 

我用它像這樣:

println(if2(true, 100, 200)); 

這一次,顯然編譯器不再關注在一個奇怪的地方if說法是,它編譯罰款和打印的期望值,100

然而,當我試圖println(if2(true, "true!", 200)),編譯器生成以下錯誤:

error: 'decltype(auto)' in return type deduced as 'int' here but deduced as 'char const (&)[5]' in earlier return statement 

如何解決這個錯誤得到什麼?

另外,一般來說,如果decltype(auto)在這些情況下似乎不起作用,我該如何根據分支條件語句的不同可能返回類型來聲明返回類型?

謝謝你的幫助!

注意:我使用g ++的參數-Wall -Wextra -pedantic -std=c++1y

+0

在C++中,你可以使用'condition? if_true:if_false'表達式,如果condition爲true則計算爲'if_true',否則爲'if_false'。那是你的追求? – cdhowie 2014-08-31 03:20:21

回答

1

你可以使用boost::variant

#include <boost/variant.hpp> 

template<typename T, typename U> 
auto if2(bool cond, T const& t, U const& u) 
{ 
    typedef boost::variant<T const&, U const&> vari; 
    return cond ? vari(t) : vari(u); 
} 

int main() 
{ 
    println(if2(rand() % 2 == 0, "true", 200)); 
} 

Demo

+0

我選擇了這個答案,因爲它實際上是編譯的。其他答案非常有幫助和信息量很大,但是他們中沒有一個真正獲得了代碼的工作。謝謝你們! – alexandergunnarson 2014-08-31 13:46:56

2

對我來說,我會使用三元運算符。 (<expression>? <value-if-true>: <value-if-false>)

用法:

println("%d", (true? 100: 200)); 
+0

如果我想要做:'println(「%_ what_?」,cond?orange:apple);'? 「桔子」和「蘋果」互不相容的地方。另外,我應該在'_what_'地方寫什麼? – Nawaz 2014-08-31 03:45:48

+0

您應該使用C++標準'iostream'庫,其中包含函數'std :: cout'。用法:'std :: cout <<(cond?orange:apple);''std :: cout'函數被重載以接受許多不同的類型。 – chucksys 2014-08-31 03:48:35

+2

@chucksys:但是如果orange不能轉換爲apple的類型,並且apple不能轉換爲orange的類型,那麼語句就不會編譯。 – 2014-08-31 03:56:42

1

你不能真正解決這個錯誤在香草C++,因爲超載會發生分辨率在編譯時。例如:

void foo(int a) { } 
void foo(char const * a) { } 

void bar(bool b) 
{ 
    foo(if2(b, "true!", 200)); 
} 

編譯器需要知道哪些foo()在編譯時調用,它不能做到這一點,如果結果if2()類型評估爲在編譯時不知道。因此,lambda必須返回某種特定類型,這意味着真實表達式和虛假表達式必須是相同的類型。

我會建議使用三元運算符?:代替:

void bar(bool b) 
{ 
    foo(b ? "true!" : 200); 
} 

這仍然無法編譯,但你會得到一個更爲清楚的錯誤消息:

error: operands to ?: have different types ‘const char*’ and ‘int’ 

此外,三元表達式可以隱含地將其中一個操作數轉換爲與另一個操作數的類型兼容,而lambda返回類型的演算並不那麼聰明:

// error: inconsistent types ‘int’ and ‘double’ deduced for lambda return type 
auto x = []() { if (true) { return 0; } else { return 0.0; } }; 

// This works; y will be a double and the int would be implicitly converted. 
auto y = true ? 0 : 0.0;