[英]Is it possible to define a variable that can be set only once?
I know of const, that can't be changed after creation.我知道 const,创建后无法更改。 But I was wondering if there is a way to declare a variable that you set only once and after that, can't overwrite.但我想知道是否有一种方法可以声明一个你只设置一次并且之后不能覆盖的变量。 In my code, I would like to avoid the bool
variable by having an nFirst
that, once set to nIdx
, can't be set to the new value of nIdx
.在我的代码中,我想通过设置一个nFirst
来避免bool
变量,该变量一旦设置为nIdx
,就不能设置为nIdx
的新值。
My code:我的代码:
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++;
}
Pretty easy to roll your own. 很容易自己动手。
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;
};
Then just use the wrapper class for your variable. 然后只需使用包装类作为变量。
SetOnce<int> nFirst(0);
nFirst= 1;
nFirst= 2;
nFirst= 3;
std::cout << nFirst.get() << std::endl;
Outputs: 输出:
1 1
I would like to avoid the bool variable 我想避免bool变量
You can check nFirst
itself, based on the fact that it won't be set a negative number. 你可以检查nFirst
本身,因为它不会被设置为负数。 Such as: 如:
int nFirst = -1;
int nIdx = 0;
BOOST_FOREACH(Foo* pFoo, aArray)
{
if (pFoo != NULL)
{
pFoo->DoSmth();
if (nFirst == -1)
{
nFirst = nIdx;
}
}
nIdx++;
}
Your question is about avoiding the bool but also implies the need for const-ness. 你的问题是关于避免bool,但也意味着需要constor。
To avoid the bool, I'd use a boost::optional like this: 为了避免bool,我会像这样使用boost :: optional:
boost::optional<int> nFirst;
// ..
if (!nFirst) nFirst = nIdx;
// and now you can use *nFirst to get its value
Then, you can enforce logical (rather than literal) const-ness like this: 然后,您可以强制执行逻辑(而不是文字)const-ness,如下所示:
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
Using const_cast
is not the safest practice, but in your particular case and as long as you only do it once it'd be OK. 使用const_cast
不是最安全的做法,但在你的特定情况下,只要你只做一次就可以了。 It simplifies both your code and your intentions: you do want a const, it's just that you want to defer it's initialisation for a bit. 它简化了你的代码和你的意图:你确实想要一个const,只是你想要推迟它的初始化。
Now, as songyuanyao suggested, you could directly use an int instead of a boost::optional, but the latter makes your intention explicit so I think it's better this way. 现在,正如songyuanyao建议的那样,你可以直接使用int而不是boost :: optional,但是后者会使你的意图明确,所以我认为这样做更好。 In the end of day this is C++ while songyuanyao's solution is really a C-style one. 在一天结束时,这是C ++,而songyuanyao的解决方案实际上是C风格的解决方案。
Similar to cocarin's , but throws exception instead of silently ignoring assignment: 与cocarin相似,但抛出异常而不是默默地忽略赋值:
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
This is set once template.这是设置一次模板。 You can use this class as assurance that the value will be set and saved only once.您可以使用这个 class 来保证该值只会被设置和保存一次。 Every next try will be canceled.每次下一次尝试都将被取消。
#include <iostream>
using namespace std;
template <class T>
class SetOnce;
template<class T>
std::ostream& operator<<( ostream& os, const SetOnce<T>& Obj );
template <class T>
class SetOnce
{
public:
SetOnce() {set = false; }
~SetOnce() {}
void SetValue(T newValue) { value = !set ? newValue : value; set = true; }
private:
T value;
bool set;
friend std::ostream& operator<< <>( ostream& os, const SetOnce& Obj );
public:
SetOnce<T>& operator=( const T& newValue )
{
this->SetValue(newValue);
return *this;
}
};
template<class T>
std::ostream& operator<<( ostream& os, const SetOnce<T>& Obj )
{
os << Obj.value;
return os;
}
Use case:用例:
int main()
{
SetOnce<bool> bvar;
SetOnce<int> ivar;
SetOnce<std::string> strvar;
std::cout<<"initial values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
bvar = false; //bvar.SetValue(false);
ivar = 45; //ivar.SetValue(45);
strvar = "Darth Vader"; //strvar.SetValue("Darth Vader");
std::cout<<"set values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
bvar = true; //bvar.SetValue(true);
ivar = 0; //ivar.SetValue(0);
strvar = "Anakin"; //strvar.SetValue("Anakin");
std::cout<<"set again values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.