2010-08-09 63 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;