Подтвердить что ты не робот

Можно ли определить переменную, которая может быть установлена ​​только один раз?

Я знаю о 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++;
    }
4b9b3361

Ответ 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

Онлайн-демонстрация