2016-03-04 13 views
17

Conosco const, che non può essere modificato dopo la creazione. Ma mi stavo chiedendo se esiste un modo per dichiarare una variabile che si imposta solo una volta e, successivamente, non può sovrascrivere. Nel mio codice, vorrei evitare la variabile bool avendo uno nFirst che, una volta impostato su nIdx, non può essere impostato sul nuovo valore di nIdx.È possibile definire una variabile che può essere impostata solo una volta?

Il mio codice:

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

Nessuno built-in per quanto ne so, ma si può rotolare la propria classe questo lo fa abbastanza facilmente. –

+0

No, non è possibile con le funzioni standard. –

+2

Puoi creare la tua classe per questo. Ma l'approccio booleano originale è ciò che anche questa classe dovrà usare_, quindi non c'è differenza nelle prestazioni. –

risposta

11

Vorrei evitare la variabile bool

È possibile controllare nFirst stessa, sulla base del fatto che non sarà impostato un numero negativo . Ad esempio:

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

@eugenesh qualsiasi variabile con prefisso ** const ** non può essere modificata, ad es. ** const double pi = 3.141592653; ** –

+2

Questo sembra l'approccio più diretto e evita in modo definitivo il valore booleano. Grazie! – tzippy

+0

puoi anche enum ** enum bool {false, true} ** ** enum color {rosso = 1, blu = 16, verde = 256} ** e puoi avere const enum o typedef enum. –

12

Abbastanza facile da rotolare.

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

Quindi utilizzare solo la classe wrapper per la variabile.

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

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

Uscite:

+1

@ Jarod42 Fisso, usava un bool per primo per seguirlo. – lcs

0

la tua domanda è su come evitare il bool, ma implica anche la necessità di const-ness.

Per evitare il bool, userei un boost :: optional come questo:

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

Quindi, è possibile far rispettare logica (piuttosto che letterale) const-ness come questo:

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 

Utilizzando const_cast non è la pratica più sicura, ma nel tuo caso particolare e finché si fa solo una volta che sarebbe stato OK. Semplifica sia il tuo codice che le tue intenzioni: vuoi un const, è solo che vuoi rimandare l'inizializzazione per un po '.

Ora, come songyuanyao suggerito, è possibile utilizzare direttamente un int invece di un boost :: facoltativa, ma quest'ultimo rende la vostra esplicita intenzione quindi penso che sia meglio così. Alla fine del giorno questo è C++ mentre la soluzione di songyuanyao è davvero in stile C.

+3

Un 'opzionale' non evita veramente un' bool', lo nasconde all'interno di un'altra classe. – jxh

+0

Non sta usando 'const_cast' per modificare il comportamento indefinito dell'oggetto costante? http://stackoverflow.com/q/14154382 – GingerPlusPlus

0

Simile a cocarin's, ma genera un'eccezione invece di assegnazione in silenzio ignorare:

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

Usage:

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

Online demo

Problemi correlati