2017-04-24 106 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());