2010-08-09 62 views
7

我想你們很多人都有這樣的代碼的地方:使用C變量初始化期間++ lambda函數

int foo; 
switch (bar) { 
    case SOMETHING: foo = 5; break; 
    case STHNELSE: foo = 10; break; 
    ... 
} 

但是這個代碼有一些缺點:

  • 你可以很容易忘記了「破發」
  • foo變量不是const的,而應該是
  • 它只是不漂亮

於是我開始想知道是否有「改善」這種代碼的方式,我得到了這個小想法:

const int foo = [&]() -> int { 
    switch (bar) { 
    case SOMETHING: return 5; 
    case STHNELSE: return 10; 
    ... 
    } 
}(); 

注:第一對括號它不是強制性的,但MSVC++不支持這個

你可以使用與if-else相同的技巧,其中三元運算符太複雜,需要通過指針傳遞的變量被初始化(如DirectX函數)等。

我的問題是:

  • 這段代碼有什麼問題,我沒有看到?
  • 你發現它比上面的更好嗎?
  • g ++似乎內聯函數,但是您認爲所有編譯器都會這樣做嗎?

編輯:這就是我所說的 「DirectX的功能」

_xAudio2 = [&]() -> std::shared_ptr<IXAudio2> { 
    IXAudio2* ptr = nullptr; 
    if (FAILED(XAudio2Create(&ptr, xAudioFlags, XAUDIO2_DEFAULT_PROCESSOR))) 
     throw std::runtime_error("XAudio2Create failed"); 
    return std::shared_ptr<IXAudio2>(ptr, [](IUnknown* ptr) { ptr->Release(); }); 
}(); 
+4

巧妙的把戲!但我會更進一步,並將lambda變成一個名爲「int EnumToFoo(Enum)」的函數:調用函數中的混亂程度較低,並自動用一個描述性良好的名稱進行記錄;)。 – Sjoerd 2010-08-09 10:23:53

+0

我與sjoerd - 我總是重構任何映射函數 - 開關或否則 – StuartLC 2010-08-09 10:32:32

+1

在這種情況下,它可能是值得編碼一個外部函數,但我沒有看到自己創建一個函數只是爲了構建一個DirectX對象,例如 – Tomaka17 2010-08-09 10:59:22

回答

3

這是在其他語言中一個相當普遍的技術。幾乎Scheme的每個高級功能都是根據立即調用的lambda表達式來定義的。

在JavaScript中,它是「模塊模式」的基礎,例如,

var myModule = (function() { 

    // declare variables and functions (which will be "private") 

    return { 
     // populate this object literal with "public" functions 
    }; 

})(); 

所以一個匿名函數聲明,並立即打電話,讓任何內部細節被隱藏的,只有返回值暴露在外。

唯一的缺點是,在隨機讀取代碼時,return語句似乎是從外部函數返回的(在Java lambda戰爭期間對此存在激烈的爭論)。但這只是一旦你的語言有lambda表達式,你必須習慣。

在像C++這樣的命令式語言中有很多語言特性,它們能從返回值中獲益(而不是像void函數那樣)。例如,if有另一種選擇,第三運營商expr ? a : b

在Ruby中,幾乎所有的語句都可以被評估,因此不需要單獨的語法來提供返回值。如果C++以這種方式工作,這將意味着這樣的事情:

auto result = try 
{ 
    getIntegerSomehow(); 
} 
catch (const SomeException &) 
{ 
    0; 
} 
+0

謝謝,我不習慣使用函數式語言 – Tomaka17 2010-08-09 10:55:20

0

我在這種情況下根本沒有看到任何使用開關盒的理由。任何像樣的編譯器都會像switch開關一樣用if語句生成一樣快的代碼。

if(bar == SOMETHING) 
    foo = 5; 
else if(bar == STHNELSE) 
    foo = 10;