2017-04-24 350 views
4

以下基本代碼是一個相當大的程序的一部分有條件初始化一個const變量

const int x = foo() == 0 ? bar() : foo(); 

foo()是一個非常昂貴和複雜的功能,所以我無法將它稱爲性能的兩倍,也可能會產生競爭條件並因此獲得不同的值(可能涉及讀取外部資源)。

我想盡可能使代碼儘可能易讀,如果可能的話儘可能短。一種選擇是:

const int foo_ = foo(), x = foo_ == 0 ? bar() : foo_; 

在另一方面,我想避免那種時間變量,主要是因爲foo()可能依賴於外部資源,因此使用foo_在代碼的其餘部分緩存值無效。

我發佈了我現在使用的解決方案,但我想知道是否有更好的選項(沒有或幾個代碼混亂,同一範圍內沒有時間變量,可讀性...)。提前致謝! PS:它必須至少遵循C++ 11標準,因爲它屬於跨平臺項目。我知道它可能是基於觀點的,但考慮到以前關於簡單性(而不是混亂的代碼)和避免時間變量(不是爲了可讀性,而是爲了代碼安全性)的陳述,我想知道解決這個問題的選項。

最終解決

閱讀所有的答案和評論後,我做了輕微的修改,以接受的答案,從而結束如下(註釋是開放的進一步細化):

static const auto fn_zero_conditional_init = []() { 
    const int foo_ = foo(); 
    return foo_ ? foo_ : bar(); 
}; 
const int x = fn_zero_conditional_init(); 

如果代碼增長並且我不得不重新使用lambda函數,我會考慮將它移動到匿名命名空間或庫範圍函數。感謝大家的貢獻!

+1

三元運算符在寫入時可能看起來更好,但一個月後回到代碼中時,它們是破譯的噩夢,尤其是如果您自己沒有寫出它們。可讀性並不總是適用於短代碼,並且可能需要添加註釋 –

+0

請解釋爲什麼您認爲「時態」變量阻礙了「代碼安全性」,特別是比聰明,難以理解的「技巧」更重要? –

+0

我同意時態變量更容易理解,我只是想避免由於這種變量的存在而使用無效狀態的機會(緩存'foo()')的返回值)。這就是爲什麼我問這個問題,是否有機會獲得兩全其美:可讀性和安全性? – cbuchart

回答

1

由於它是基於觀點的問題,我會去的:

auto get_the_correct_x=[](){ 
    const auto temp=foo(); 
    return temp==0?bar():temp; 
} 
const auto x=get_the_correct_x(); 

一個好的名稱,而不是get_the_correct_x甚至會更明確,而不僅僅是試圖玩沒有命名的lambda。

+0

如果你使用了很多,我建議使它成爲一個合適的方法/函數,而不是lambda表達式。 – chtz

+0

到目前爲止,這是我發現更有用的解決方案,可能比內聯lambda大,但會生成更多可讀代碼,謝謝!我會用我使用的最終實施來更新這個問題 – cbuchart

4

到目前爲止,我已經找到了解決辦法是使用lambda功能,如:

const int x = [](int n) { return n == 0 ? bar() : n; }(foo()); 
+1

這個代碼不會使用'n'作爲臨時變量嗎? – alirakiyan

+0

是的,但正如問題中所述,我對時間變量的關注是由於foo()的性質超過了時間變量本身(如果使用了時間變量,它的值可能會過時) 。另一方面,如果不是'int',我會使用一個帶有複製構造函數的類型,那麼我會改用'const&'來代替。 – cbuchart

+0

這太複雜了,並不容易理解。 –

4

如果你樂於使用gcc extensions,那麼你可以這樣寫:

const int x = foo() ?: bar(); 
+1

看起來不錯,但不幸的是我必須遵循標準,因爲它是一個跨平臺的代碼。我會考慮gcc代碼,謝謝!很高興在未來的標準中看到它。 – cbuchart

3

什麼一個簡單的:

const int temp_foo = foo(); 
const int x = (temp_foo == 0) ? bar() : temp_foo; 
+0

Tahnks,但對不起,正如問題中提到的,我想避免時間變量。 – cbuchart

+1

@cbuchart:人們會認爲它會被優化掉,而且我覺得它比lambda更容易混淆。 – Unimportant

+0

@cbuchart:_「我想避免[臨時]變量」_爲什麼?這是最明顯,實用和正常的解決方案。可以由您的編譯器和人員理解。它應該絕對沒有運行時間的損失(爲什麼會這樣?你有相同數量和數量的對象) –

2

除了lambda,如果這種情況不會發生多次在你的程序,你可以換功能foo()與功能,讓我們說conditionalFoo()

int conditionalFoo() { 
    int result = foo(); 
    if (result==0) 
    result = bar(); 
    return result; 
} 
... 
const int x = conditionalFoo(); 
+0

您可以在函數中使用'return bar();'。 – quamrana

+0

另外,您可以傳遞'foo()'作爲參數(使其更類似於OP提出的lambda表達式解決方案)。那麼這個方法應該被命名爲'int conditionalBar(int foo)'。 – chtz

3

基本上,你想要Elvis operator,但C++沒有。這是可能想再次使用的那種東西。所以,而不是你提出的lambda解決方案,我選擇一個通用的解決方案。

例如

#include <functional> 

int func_elvis (std::function<int()> func1, std::function<int()> func2) { 
    int tmp = func1(); 
    return tmp ? tmp : func2(); 
} 

然後將其用於像

const int x = func_elvis(foo, bar); 

如果您希望自己調用的函數,你可以做

#define ELVIS(A, B) func_elvis([](){ return A; }, [](){ return B; }) 

,並使用它像

const int x = ELVIS(foo(), bar());