How can I make a variable always equal to the result of some calculations?

前端 未结 12 1771
傲寒
傲寒 2021-02-02 05:34

In math, if z = x + y / 2, then z will always change whenever we replace the value of x and y. Can we do that in programming

相关标签:
12条回答
  • 2021-02-02 05:46

    So a big problem that I see with the lambda solutions provided is that z is calculated each time that it is inspected even if neither x nor y has changed. To get around this you really need to link these variables. I would suggest doing that via class:

    class foo {
        int x;
        int y;
        int z;
        void calculate() { z = (x + y) / 2; }
        friend istream& operator >>(istream& lhs, foo& rhs);
    public:
        void set_x(const int param) {
            x = param;
            calculate();
        }
        int get_x() const { return x; }
        void set_y(const int param) {
            y = param;
            calculate();
        }
        int get_y() const { return y; }
        int get_z() const { return z; }
    };
    
    istream& operator >>(istream& lhs, foo& rhs) {
        lhs >> rhs.x >> rhs.y;
        rhs.calculate();
        return lhs;
    }
    

    This will recalculate z each time x or y is set. This is a good solution if you access z frequently, and x and y are set infrequently. If x and y are set frequently or calculate is expensive you might consider:

    class foo {
        int x;
        int y;
        int z;
        bool dirty;
        void calculate() { z = (x + y) / 2; }
        friend istream& operator >>(istream& lhs, foo& rhs);
    public:
        void set_x(const int param) {
            x = param;
            dirty = true;
        }
        int get_x() const { return x; }
        void set_y(const int param) {
            y = param;
            dirty = true;
        }
        int get_y() const { return y; }
        int get_z() const { 
            if(dirty) {
                calculate();
            }
            return z;
        }
    };
    
    istream& operator >>(istream& lhs, foo& rhs) {
        lhs >> rhs.x >> rhs.y;
        rhs.dirty = true;
        return lhs;
    }
    

    Note that I've included an extraction operator, so whichever you choose your code can turn into something as simple as:

    foo xyz;
    
    cin >> xyz;
    cout << xyz.get_z();
    
    0 讨论(0)
  • 2021-02-02 05:50

    You can get what you're asking for by using macros:

    {
        int x, y;
    #define z (x + y)
        /* use x, y, z */
    #undef z
    }
    

    The #undef is for a little sanity. For more sanity, don't use macros at all, and go with one of the other answers, and deal with the extra verbosity.

    Although a class with a custom operator int would work in a lot of cases ... hmm.

    0 讨论(0)
  • 2021-02-02 05:53

    What you're describing is late binding, which a compiled language like C++ can do only with difficulty. In an interpreted language, all you need is the ability to set z to an unevaluated expression and delay binding of z's value until the calculation is needed, typically signaled by a call to a function that forces the evaluation such as eval in Lisp. In my Expert System's rules language, I have not only eval but noeval, which protects its argument from one level of evaluation. That provides granular control over the binding, with some sub-expressions being evaluated (bound) and others not, if desired. This is not applicable to your scenario, but it sets the scene in terms of the language landscape.

    0 讨论(0)
  • 2021-02-02 05:54
    1. You create a function for that.
    2. You call the function with the appropriate arguments when you need the value.

    int z(int x, int y)
    {
       return (x + y);
    }
    
    
    int x;
    int y;
    
    // This does ot work
    // int z{x + y};
    
    cin >> x;
    cin >> y;
    cout << z(x, y);
    
    0 讨论(0)
  • 2021-02-02 05:58

    Edit: While I fully answered the question as asked, please have a look at Artelius' answer, too. It addresses some issues my answer doesn't (encapsulation, avoidance of redundancies, risks of dangling references). A possible optimisation, if calculation is expensive, is shown in Jonathan Mee's answer.


    You mean something like this:

    class Z
    {
        int& x;
        int& y;
    public:
        Z(int& x, int& y) : x(x), y(y) { }
        operator int() { return x + y; }
    };
    

    The class delays calculation of the result until casted as int. As cast operator is not explicit, Z can be used whenever an int is required. As there's an overload of operator<< for int, you can use it with e. g. std::cout directly:

    int x, y;
    Z z(x, y);
    std::cin >> x >> y;
    if(std::cin) // otherwise, IO error! (e. g. bad user input)
        std::cout << z << std::endl;
    

    Be aware, though, that there's still a function call (the implicit one of the cast operator), even though it is not visible. And actually the operator does some true calculations (rather than just accessing an internal member), so it is questionable if hiding away the function call really is a good idea...

    0 讨论(0)
  • 2021-02-02 05:59

    This sounds like the XY problem (pun intended).

    From the sound of it, you are not really writing code according to good object oriented practices. I would advise you not to use the "tricks" other people have suggested, but to actually learn how to make better use of OO structure.

    Before I go into that, note that assignment is distinct from an equality relation. The = in C++ is assignment, which is not the same as the = in maths. There are some (but not many) programming languages that do support equality relations, but C++ is not one of them. The thing is, adding support for equality relations introduces a heap of new challenges, so it's not as simple as "why isn't it in C++ yet".

    Anyway, in this case, you should probably be encapsulating your related variables in a class. Then you can use methods to obtain the "up-to-date" information. For example:

    class Player {
        std::vector<int> inventory;
        int cash;
    public:
        int inventory_total();
        int net_worth();
    }
    
    //adds up total value of inventory
    int Player::inventory_total() {
        int total = 0;
        for(std::vector<int>::iterator it = inventory.begin(); it != inventory.end(); ++it) {
            total += *it;
        }
        return total;
    }
    
    //calculates net worth
    int Player::net_worth() {
        //we are using inventory_total() as if it were a variable that automatically
        //holds the sum of the inventory values
        return inventory_total() + cash;
    }
    
    
    ...
    
    
    //we are using net_worth() as if it were a variable that automatically
    //holds the sum of the cash and total holdings
    std::cout << player1.net_worth();
    

    I admit that adding this behaviour to a class is quite a bit more complicated than saying z = x + y, but it really is only a few extra lines of code.

    That would be very annoying and error prone if you forgot to call the function somewhere.

    In this case the object doesn't have a net_worth member variable, so you can't accidentally use it instead of calling the function.

    0 讨论(0)
提交回复
热议问题