在声明之后是否有一些忍者技巧使变量保持不变?

Tho*_*ini 47 c++ const-correctness c++11

我知道答案是99.99%没有,但我认为值得一试,你永远不会知道.

void SomeFunction(int a)
{
    // Here some processing happens on a, for example:
    a *= 50;
    a %= 10;
    if(example())
       a = 0;
    // From this point on I want to make "a" const; I don't want to allow
    // any code past this comment to modify it in any way.
}
Run Code Online (Sandbox Code Playgroud)

我可以做一些类似的东西const int b = a;,但它并不是真的相同,它会造成很多混乱.只接受C++ 0x解决方案.

编辑:另一个不那么抽象的例子,那个让我问这个问题的例子:

void OpenFile(string path)
{
    boost::to_lower(path);
    // I want path to be constant now
    ifstream ...
}
Run Code Online (Sandbox Code Playgroud)

编辑:另一个具体的例子:在并行部分中重新获取变量的常量.

bdo*_*lan 46

您可以将代码移动a到另一个函数中:

int ComputeA(int a) {
  a *= 50;
  a %= 10;
  if (example())
    a = 0;
  return a;
}

void SomeFunction(const int a_in) {
  const int a = ComputeA(a_in);
  // ....
}
Run Code Online (Sandbox Code Playgroud)

否则,在编译时没有很好的方法可以做到这一点.

  • 这默默地走私了这样一个事实:"a"实际上是一个不同的对象. (6认同)
  • 在重要的情况下,可以使用const引用 (2认同)

Jar*_*Par 39

一种解决方案是将所有突变代码分解为lambda表达式.执行lambda表达式中的所有变异,并将结果分配给const int方法范围中的a.例如

void SomeFunction(const int p1) { 
  auto calcA = [&]() {
    int a = p1;
    a *= 50;
    a %= 10;
    if(example())
       a = 0;
    ..
    return a;
  };
  const int a = calcA();
  ...
}
Run Code Online (Sandbox Code Playgroud)

  • 你能定义并调用lambda吗?`const int a = [&]() - > int {...}();`?我没有支持它们的编译器. (4认同)
  • @Steve:gcc45似乎并不反对这种表示法,尽管我并不准备用任何实际的证据来支持它. (2认同)

mb1*_*b14 11

我以前使用的模式是用_"隐藏"参数,因此代码变为

void SomeFunction(int _a)
{
    // Here some processing happens on a, for example:
    _a *= 50;
    _a %= 10;
    if(example())
       _a = 0;

    const int a = _a;
    // From this point on I want to make "a" const; I don't want to allow
    // any code past this comment to modify it in any way.
}
Run Code Online (Sandbox Code Playgroud)

如果需要,您还可以仅使用const变量并创建一个函数来计算a的新值.我更倾向于不"重用"变量尽可能多地使我的变量变为不可变:如果你改变了某些东西的值,那么给它一个新的名字.

void SomeFunction(const int _a)
{
    const int a = preprocess(_a);
    ....

}
Run Code Online (Sandbox Code Playgroud)

  • @Andreas:引入新功能也引入了复杂性并且使用lambda似乎过于庞大.请注意,*每个*涉及函数的解决方案都会引入第二个变量.我的解决方案可以看作轻量级lambda版本.但是,我个人可能也会使用一个函数,或者不会让自己处于这种情况.但问题是问忍者技巧,所以我给了一个忍者技巧;-). (2认同)

dir*_*tly 10

为什么不将代码重构为两个单独的函数.一个返回修改的a,另一个返回此值(不改变它).

您可以将对象包裹在持有者类对象周围并使用此持有者.

template <class T>
struct Constify {
    Constify(T val) : v_( val ) {}
    const T& get() const  { return v_; }
};

void SomeFuncion() {
    Constify ci( Compute() ); // Compute returns `a`
    // process with ci
}
Run Code Online (Sandbox Code Playgroud)

您的示例有一个简单的解决方法:重构.

// expect a lowercase path or use a case insensitive comparator for basic_string
void OpenFile(string const& path)  
{        
    // I want path to be constant now
    ifstream ...
}

OpenFile( boost::to_lower(path) ); // temporaries can bind to const&
Run Code Online (Sandbox Code Playgroud)

  • +1 该函数具有两个具有不同常量要求的独立上下文这一事实清楚地表明该函数需要拆分为两个函数。 (2认同)

Mar*_*k B 6

我实际上并不建议这样做,但您可以使用创意变量阴影来模拟您想要的东西:

void SomeFunction(int a)
{
    // Here some processing happens on a, for example:
    a *= 50;
    a %= 10;
    if(example())
       a = 0;
    {
        const int b = a;
        const int a = b;  // New a, shadows the outside one.
        // Do whatever you want inside these nested braces, "a" is now const.
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你也可以对引用做同样的事情。 (3认同)

alv*_*vin 5

如果您只是想避免使用其他名称,这可能是一种方法.我建议你在使用之前再三考虑.

int func ()
{
    int a;
    a %= 10;

const int const_a = a;
#define a const_a

    a = 10;  // this will cause an error, as needed.
#undef a
}
Run Code Online (Sandbox Code Playgroud)

  • +1绝对邪恶的代码,但绝对和'忍者技巧' (5认同)