web-dev-qa-db-ja.com

宣言後に変数を定数にする忍者のトリックはありますか?

答えは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.
}

const int b = a;、しかしそれは実際には同じではなく、多くの混乱を引き起こします。 C++ 0xのみのソリューションでも問題ありません。

[〜#〜] edit [〜#〜]:別の抽象化されていない例で、私にこの質問をさせた例:

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

[〜#〜] edit [〜#〜]:別の具体的な例: 並列セクションの変数の定数の再取得 =。

52
Thomas Bonini

1つの解決策は、すべての突然変異コードをラムダ式に因数分解することです。ラムダ式ですべての変更を行い、結果をメソッドスコープのconst intに割り当てます。例えば

void SomeFunction(const int p1) { 
  auto calcA = [&]() {
    int a = p1;
    a *= 50;
    a %= 10;
    if(example())
       a = 0;
    ..
    return a;
  };
  const int a = calcA();
  ...
}
38
JaredPar

コードを移動して、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);
  // ....
}

それ以外の場合は、コンパイル時にこれを行うための良い方法はありません。

46
bdonlan

私が使用していたパターンは、_で引数を「隠す」ことなので、コードは

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.
}

必要に応じて、const変数のみを使用して、aの新しい値を計算する関数を作成することもできます。変数を "再利用"しないようにする傾向があります。変数をできるだけ不変にします。何かの値を変更した場合は、新しい名前を付けます。

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

}
11
mb14

コードを2つの別々の関数にリファクタリングしてみませんか。 1つは変更されたaを返し、もう1つはこの値を操作します(これを変更することなく)。

オブジェクトをホルダークラスオブジェクトにラップして、このホルダーを操作することもできます。

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
}

あなたの例には簡単な修正があります:リファクタリング。

// 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&
10
dirkgently

これは、別の名前を避けようとしているだけの場合、1つの方法です。これを使用する前に、よく考えることをお勧めします。

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
}
5
alvin

実際にこれを行うことはお勧めしませんが、クリエイティブな変数シャドウイングを使用して、必要なものをシミュレートできます。

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.
    }
}
4
Mark B

答えはかなりしっかりしていましたが、正直に言って、これを使用するのに良い状況は本当に考えられません。しかし、基本的にあなたがしていることである定数を事前計算したい場合は、いくつかの主な方法がありますこの。

まず、次のことができます。したがって、この場合、コンパイラーは単にCompileA#を50、100、および150に設定します。

const int CompileA1 = EarlyCalc(1);
const int CompileA2 = EarlyCalc(2);
const int CompileA3 = EarlyCalc(3);

int EarlyCalc(int a)
{
    a *= 50;
    return a;
}

これを超えると、これを処理する方法が非常に多くなります。他の人が言っているように私は提案が好きだった。

void SomeFunc(int a)
{
    const int A = EarlyCalc(a);
    //We Can't edit A.
}

しかし、別の方法は...

SomeFunc(EarlcCalc(a));

void SomeFunc(const int A)
{
    //We can't edit A.
}

あるいは..

SomeFunction(int a)
{
    a *= 50;
    ActualFunction(a);
}

void ActualFunction(const int A)
{
    //We can't edit A.
}
0
Jeremy Trifilo