Как сделать переменную всегда равной результату некоторых вычислений? - PullRequest
57 голосов
/ 28 марта 2019

В математике, если z = x+y/2, то z всегда будет меняться всякий раз, когда мы заменяем значения x и y. Можем ли мы сделать это в программировании без необходимости конкретного обновления z всякий раз, когда мы меняем значения x и y?

Я имею в виду что-то подобное не будет работать, верно?

int x;
int y;
int z{x + y};
cin >> x;
cin >> y;
cout << z;

Если вы не уверены, зачем мне это нужно, я хочу, чтобы показанная переменная работала, и чтобы она автоматически обновлялась при изменении переменной rhs.

Как и при убийстве крипа и получении золота, показанная чистая стоимость (деньги + стоимость собственных предметов) меняется. Или измеритель скорости автомобиля, который меняется в зависимости от скорости или скорости движения.

Ответы [ 12 ]

3 голосов
/ 28 марта 2019

Вы можете написать класс, который инкапсулирует его состояние, чтобы обновлять его либо при мутации, либо возвращать правильный результат при запросе:

#include <iostream>

template<typename T, typename U, typename V>
class DynamicCalc
{
public:
    DynamicCalc(const T& func, const U& memberOne, const V& memberTwo) :
        _func(func)
      , _memberOne(memberOne)
      , _memberTwo(memberTwo)
    {

    }

    void SetMemberOne(const U& memberOne) { _memberOne = memberOne; }
    void SetMemberTwo(const U& memberTwo) { _memberTwo = memberTwo; }
    auto Retrieve() { return _func(_memberOne, _memberTwo); }

    U GetMemberOne() { return _memberOne; }
    V GetMemberTwo() { return _memberTwo; }

private: 
    T _func;

    U _memberOne;
    V _memberTwo;
};

int main() {

    auto func = [](int x, int y) {
        return x + y;
    };
    DynamicCalc<decltype(func), int, int> c(func, 3, 5);

    c.SetMemberOne(5);
    std::cout << c.Retrieve();
}

По правде говоря, если вы счастливы, что вычисление произойдет, когда значениетребуется повторно, тогда методы получения / установки не нужны.

0 голосов
/ 03 апреля 2019

Хорошо, позвольте мне, наконец, написать правильный и единственно верный ответ на поставленный вами вопрос:

Вы не можете.

Вы не можете написать z = x + y и затем весь код, используя z, магически перезапускается всякий раз, когда x или y изменяется.

Так что же можно сделать?

Как упоминалось в других ответах, есть несколько шаблонов для выражения того, что вы хотите, чтобы изменения x и y вызывали некоторые обновления, но в любом случае вам нужно, чтобы эти обновления происходили более или менее явно.

В зависимости от варианта использования вы можете:

  • В любом случае это значение необходимо пересчитать в любое время. Например. если вы пишете игру и перерисовываете экран каждый кадр, то, вероятно, достаточно просто убедиться, что вы случайно не держите значение z между кадрами. Знайте, когда ваша ценность может измениться, а когда нет. Используете ли вы функцию, лямбду, метод класса или просто повторяете выражение - это в основном эстетическое решение. Если возможно, это лучший подход, потому что он полностью прозрачен.

    Например, в гоночной игре вы, скорее всего, обновите текущую скорость в начале расчета нового тика, а затем будете использовать обновленное значение при вычислении движения вашего автомобиля, при перерисовке индикатора скорости, при создании размытия в движении, и так далее. Вам не нужна магия и даже не функция, вы можете просто использовать переменную, потому что вы знаете, что ваша скорость не изменится за один кадр.

  • Вызовите обновление явно. Используйте его, например. когда у вас есть один виджет, вам нужно обновить. Недостатком является то, что вы должны помнить, чтобы вызвать обновление, что несколько хрупко, но с другой стороны - это очень просто. Середина - интегрировать вызов обновления с сеттером, что делает его своего рода реализацией Observer для бедного человека.

  • Использовать шаблон Observer (см. Также сигналы и слоты, это один из способов реализации Observer). Используйте это, например. когда у вас есть много виджетов для обновления, или вы создаете их динамически. Старайтесь не использовать его, когда один из вышеперечисленных работает, они способ проще.

  • Использовать выделенную библиотеку реактивного программирования . Поскольку такие вещи существуют, я чувствую себя обязанным упомянуть об этом. Однако я, честно говоря, не вижу ни одного приложения, где бы я его использовал. В основном это кажется сложным способом отстрелить ноги. Неявные обновления будут иметь неприятные последствия, и вам придется все переписать. Только не, не в C ++. Что важно: хотя этот подход наиболее близок к «магическому обновлению всего», он будет накладывать ограничения на то, как вы пишете свой код, и в итоге вы получите одно из вышеперечисленных решений, только более сложное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...