Можно ли определить переменную, которая может быть установлена только один раз?
Я знаю о const, который не может быть изменен после создания. Но мне было интересно, есть ли способ объявить переменную, которую вы устанавливаете только один раз и после этого не может перезаписывать.
В моем коде я хотел бы избежать переменной bool
, имея nFirst
, который после установки nIdx
не может быть установлен на новое значение nIdx
.
Мой код:
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++;
}
Ответы
Ответ 1
Я хотел бы избежать переменной bool
Вы можете проверить nFirst
самостоятельно, исходя из того, что ему не будет установлено отрицательное число. Например:
int nFirst = -1;
int nIdx = 0;
BOOST_FOREACH(Foo* pFoo, aArray)
{
if (pFoo != NULL)
{
pFoo->DoSmth();
if (nFirst == -1)
{
nFirst = nIdx;
}
}
nIdx++;
}
Ответ 2
Довольно легко сворачивать.
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
Ответ 3
Ваш вопрос об избежании bool, но также подразумевает необходимость в константе.
Чтобы избежать bool, я бы использовал boost:: optional, как это:
boost::optional<int> nFirst;
// ..
if (!nFirst) nFirst = nIdx;
// and now you can use *nFirst to get its value
Затем вы можете принудительно выполнить логическую (а не литеральную) конструкцию следующим образом:
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
- не самая безопасная практика, но в вашем конкретном случае и до тех пор, пока вы делаете это только один раз, когда все будет в порядке. Это упрощает как ваш код, так и ваши намерения: вам нужен const, просто вы хотите немного отложить его инициализацию.
Теперь, как предложил songyuanyao, вы можете напрямую использовать int вместо boost:: optional, но последнее делает ваше намерение явным, поэтому я думаю, что это лучше. В конце дня это С++, в то время как решение songyuanyao действительно является C-образным.
Ответ 4
Подобно кокарину, но вместо исключения молча игнорирует назначение:
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
Онлайн-демонстрация