我知道const,在创建之后无法更改。但我想知道是否有办法声明一个你只设置一次的变量,之后就不会覆盖。
在我的代码中,我希望避免使用bool
变量,nFirst
一旦设置为nIdx
,就无法设置为{{1}的新值}}
我的代码:
nIdx
答案 0 :(得分:13)
很容易推出自己的。
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
答案 1 :(得分:11)
我想避免使用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 :(得分:0)
你的问题是关于避免布尔,但也意味着需要保持稳定。
为了避免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,但后者会使你的意图明确,所以我觉得这样做更好。在一天结束时,这是C ++,而songyuanyao的解决方案实际上是C风格的解决方案。
答案 3 :(得分: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