简体   繁体   English

是否可以定义一个只能设置一次的变量?

[英]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

Online demo 在线演示

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.

相关问题 如何在递归 function 中只定义和初始化一次变量? - How to define and initialize a variable only once in a recursive function? 仅在函数中设置一次静态变量 - set static variable in function only once 你能用 scanf() 用#define 定义一个变量集吗? - Can you use scanf() to define a variable set with #define? 是否有可能每个类只传递一次变量但不能使它变为静态变量? - Is it possible to pass a variable only once per class but not make it static? 为什么当我将在 for 循环中定义的变量定义为全局变量时,它只在串行监视器上写入一次? - Why when I define the variable I defined in the for loop as global, it only writes once on the serial monitor? C++ - 你可以用不同的参数重载 function 但只定义一次吗? - C++ - Can you overload a function with different parameters but define it only once? 为什么不能一次定义两个指针? - Why can I not define two pointers at once? 子访问父变量/定义变量一次,在整个应用程序中使用 - Child access parent variable / Define variable once, use it in entire application 只能通过一种方法更改的C ++全局变量,可能吗? - C++ global variable that can be changed only in one method, possible? 是否可以在C ++中的表达式中定义变量? - Is it possible to define a variable in expression in C++?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM