2016-03-04 15 views
17

私はconstを知っていますが、それは作成後に変更することはできません。しかし、あなたが一度だけ設定した変数を宣言する方法があるのか​​、上書きできないのか疑問に思っていました。 私のコードでは、nIdxに設定したに設定することができないnFirstという変数を使用して、bool変数を回避したいと考えています。一度しか設定できない変数を定義することは可能ですか?

マイコード:

int nFirst = 0; 
    int nIdx = 0; 
    bool bFound = false; 
    BOOST_FOREACH(Foo* pFoo, aArray) 
    { 
     if (pFoo!= NULL) 
     { 
      pFoo->DoSmth(); 
      if (!bFound) 
      { 
       nFirst= nIdx; 
       bFound = true; 
      } 
     } 
     nIdx++; 
    } 
+5

どれも私の知る限りでは、内蔵ませんが、独自のクラスをロールバックすることができますこれは非常に簡単です。 –

+0

いいえ、標準機能では不可能です。 –

+2

独自のクラスを作成することができます。しかし、元のブール値のアプローチは、そのクラス_も使用する必要がありますので、パフォーマンスに違いはありません。 –

答えて

11

私はあなたがそれが負の数に設定されていないという事実に基づいて、nFirst自体を確認することができブール変数

を避けたいです。のような:

int nFirst = -1; 
int nIdx = 0; 
BOOST_FOREACH(Foo* pFoo, aArray) 
{ 
    if (pFoo != NULL) 
    { 
     pFoo->DoSmth(); 
     if (nFirst == -1) 
     { 
      nFirst = nIdx; 
     } 
    } 
    nIdx++; 
} 
+1

@eugenesh ** const **接頭辞を持つ変数は変更できません。 ** const double pi = 3.141592653; ** –

+2

これは最も単純なアプローチのようであり、ブール値を間違いなく避けています。ありがとうございました! – tzippy

+0

enum bool {false、true} ** ** enum color {red = 1、blue = 16、green = 256} **また、const enumまたはtypedef enumを持つことができます。 –

12

かなり簡単に自分自身をロールバックする。

template<typename T> 
class SetOnce 
{ 
public: 
    SetOnce(T init) : m_Val(init) 
    {} 

    SetOnce<T>& operator=(const T& other) 
    { 
     std::call_once(m_OnceFlag, [&]() 
     { 
      m_Val = other; 
     }); 

     return *this; 
    } 

    const T& get() { return m_Val; } 
private: 
    T m_Val; 
    std::once_flag m_OnceFlag; 
}; 

次に、変数にラッパークラスを使用してください。

SetOnce<int> nFirst(0); 
nFirst= 1; 
nFirst= 2; 
nFirst= 3; 

std::cout << nFirst.get() << std::endl; 

出力:

+1

@ Jarod42まず、ブールを使ってそれを追跡するように修正しました。 – lcs

0

あなたの質問はブール値を回避についてですが、またのconstネスの必要性を意味します。

ブール値を避けるために、私はブースト::このようなオプションを使用したい:次に

boost::optional<int> nFirst; 
// .. 
if (!nFirst) nFirst = nIdx; 
// and now you can use *nFirst to get its value 

を、あなたはこのように(リテラルではなく)論理のconstネスを強制することができます。

const boost::optional<int> nFirst; 
// .. 
if (!nFirst) const_cast<boost::optional<int>&>(nFirst) = nIdx; 
// you can use *nFirst to get the value, any attempt to change it would cause a compile-time error 

const_castを使用するのは最も安全な方法ではありませんが、特定のケースでは、一度やり直すだけでOKです。これは、コードと意図の両方を簡素化します。constを必要とします。ちょっとした初期化を延期したいだけです。

ここで、songyuanyaoが示唆しているように、boost :: optionalの代わりにintを直接使うことができますが、後者はあなたの意図を明示的にしています。終わりには、これはC++ですが、songyuanyaoのソリューションは実際にはCスタイルのソリューションです。

+3

'オプション'は 'bool'を本当に避けません。別のクラスの中に隠します。 – jxh

+0

定数オブジェクトの未定義の動作を変更するために 'const_cast'を使用していませんか? http://stackoverflow.com/q/14154382 – GingerPlusPlus

0
cocarin'sに似

、しかし静かに無視して代入するのではなく、例外をスロー:

template <typename T, typename Counter = unsigned char> 
class SetOnce { 
public: 
    SetOnce(const T& initval = T(), const Counter& initcount = 1): 
     val(initval), counter(initcount) {} 
    SetOnce(const SetOnce&) = default; 
    SetOnce<T, Counter>& operator=(const T& newval) { 
     if (counter) { 
      --counter; 
      val = newval; 
      return *this; 
     } 
     else throw "Some error"; 
    } 
    operator const T&() const { return val; } // "getter" 
protected: 
    T val; 
    Counter counter; 
}; 

使用法:

SetOnce<int> x = 42; 
std::cout << x << '\n'; // => 42 
x = 4; 
// x = 5; // fails 
std::cout << x << '\n'; // => 4 

Online demo

関連する問題