常数,但仅适用于此范围的剩余部分



我有时会遇到这样的情况:变量为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上直播

它不会使范围的所有剩余的变量保持不变,但它允许您控制变量保持不变的范围,当然,后者可以扩展到封闭范围的末尾。

最新更新