简体   繁体   中英

Determine lvalue and rvalue in C++ function

UPDATE: I revised some place, and now the problem has changed in some way.

I'm writing a C++ class. Like:

class qqq{
    map<int,int> core;
    //......
    int& operator[](int n){return core[n];};
};
int main(){
    qqq a;
    a[3]=7;a[5]=0;//Case a
    int b=a[3];//Case b
    return 0;
}

Although case A and case B are calling the same function(overloaded operator), but case a is used as an lvalue while case b is used as a rvalue.

For some reason, I want to have the effect that if 0 is passed to a[5], delete the node 5 in core. Like:

int& operator[](int n){
    if(CASE A && THE VALUE PASSED TO IT IS 0)
        core.erase(core.find(n));
    else
        return core[n];
}

Maybe my description is not accurate.

You have to always return a value which can be used as left value in the assignment expression. Therefore, I suggest to use a garbage int variable. I declared the garbage as static because we need just one instance of this variable and we don't care its value.

For example,

 class qqq{
    static int garbage;
    map<int,int> core;
    //......

    int& operator[](int n){
        if(CASE A && THE VALUE PASSED TO IT IS 0)
            return garbage;
        else
            return core[n];
    }
};

However, this solution is confusing in my point of view because the behaviour completely changes according to what you specify in the square brackets. If the value passed in input is incorrect, I would probably thrown an exception.

* EDIT *

I think you are over complicating the problem using the [] operator. You can easily solve your problem by using setter and getters. For example :

int set(int index, int value){
    if( value == 0)
        core.erase(core.find(index));
    else
        return core[index];
}

int get(int index) {
 return core[index];
}

The [] allows only for returning a reference, you don't know what is the value used in the assignment.

Here is an implementation of the proxy pattern mentioned in the comments.

Personally, I don't use this, my maps are wrapped in classes that don't provide operator[] at all, instead there are functions like .get(key, default) .init(key) , .setdefault(key, default) , etc. depending on the class.

// This code is C++11 but it's not essential to the problem.
// The current code calls copy constructors more than necessary.
#include <map>

#include <cassert>


template<class K, class V>
struct zero_map
{
    struct proxy
    {
        std::map<K, V> *container;
        K key;

        operator V()
        {
            auto it = container->find(key);
            if (it == container->end())
                return V();
            return *it;
        }
        void operator = (V value)
        {
            if (value == V())
            {
                container->erase(key);
            }
            else
            {
                // probably should use .insert() and conditionally assign
                (*container)[key] = value;
            }
        }
    };

    std::map<K, V> _inner;

    proxy operator[](K k)
    {
        return proxy{&_inner, k};
    }
};

int main()
{
    zero_map<int, int> foo;
    assert (foo._inner.size() == 0);
    foo[1] = 0;
    assert (foo._inner.size() == 0);
    foo[0] = 1;
    assert (foo._inner.size() == 1);
    foo[0] = 0;
    assert (foo._inner.size() == 0);
}

As a comment said, use a proxy class.

template<typename T, size_t BadIndex>
class Element{ // please use a more meaningful name
    public:
        Element(const size_t index): index(index){}

        operator T& (){return value;}
        operator T const&() const{return value;}

        T &operator =(const T &rhs){
            if(index != BadIndex)
                value = rhs;
            return value;
        }

        operator T const&() const{return value;}
        operator T&(){return value;}

    private:
        T value;
        const size_t index;
};

class qqq{
    public:
        std::map<int, Element<int, 5>> core;

        Element<int> &operator [](size_t index){
            auto itt = core.find(index);
            if(itt == core.end()){
                core.emplace(index, index);
                itt = core.find(index);
            }
            return (*itt).second;
        }
};

That should work, but 5 will always give you a garbage result.

You question is now clear, unfortunately you will have no way to do that is C++. operator[] is not a getter and a setter : it can only return a reference, and that reference is than used for a mere assignement. At the moment the operator returns its reference, you cannot know what value will be used for a assignement, and you can hardly know how the ref will be used.

IMHO what you need is more :

int getCore(int i) {
    return core[i];
}

void setCore(int i, int newval) {
    if (newval == 0) {
        core.erase(core.find(i));
    }
    else {
        core[i] == newval;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM