我有时会遇到这样的情况:变量为const
是有意义的,但仅适用于其范围的后半部分。例如,一个块的第一部分可能会设置值,如果我们已经"完成"设置变量,那么其余部分的可读性可能会提高
void foo() {
int n;
// Do things that result in initialization of n
freeze n; // Imaginary construct that declares "n" const for rest of scope
// Later steps that depend on 'n' but do not change it
}
有没有任何C++习语可以捕捉到这种模式?当然,块的后一部分可以移动到一个单独的函数,但可以在不移动太多东西的情况下完成吗?
您的"冻结"代码可能看起来像:
const int &refN = n;
然后使用CCD_ 2而不是CCD_ 3。你可以换个名字。
还有更复杂的解决方案,但你真的必须问问自己,付出的代价是否值得。如果你的函数太复杂了,以至于你一眼都看不到你是否修改了n
,那么你需要重构你的代码。
例如,要隐藏n
,可以执行以下操作:
{
const int &_tmp = n;
const int &n = _tmp;
// rest of code
}
但你必须问问自己这是否值得。无论谁在你之后读到代码,都会想知道你抽的是什么。
另一个选项是您的功能为:
const int n = setup_n();
将逻辑卸载到另一个函数,或lambda:
const int n = [](){
// ...logic...
return finalized_value;
}();
与其将不可变部分包装为lambda,不如将初始化部分包装为lambda并将其作为const int
?那么就没有机会改变可变的CCD_ 7。
void foo() {
const int n = []() { ;
// Do things that result in initialization of n
return initialized_n;
}();
// Later steps that depend on 'n' but do not change it
}
使用与@PSkocik的答案(现已删除)类似的方法,您可以在匿名lambda中捕获所需的变量并执行后者。您甚至可以为此定义一个可变宏,因此可以使用相对"干净"的语法捕获多个变量:
#include <iostream>
#define WITH_CONST(...) [&, __VA_ARGS__]()
#define DO ();
void foo() {
int n{1}, m{2}, z{3};
WITH_CONST(n, m) // captured variables are immutable in the scope below
{
//++n; // compile-time error
//++m; // compile-time error
++z; // z is mutable, can modify
std::cout << n << " " << m << " " << z << std::endl;
}
DO;
// n and m are not constant anymore
++n;
++m;
std::cout << n << " " << m << " " << z << std::endl;
}
int main()
{
foo();
}
在Coliru上直播
它不会使范围的所有剩余的变量保持不变,但它允许您控制变量保持不变的范围,当然,后者可以扩展到封闭范围的末尾。