简体   繁体   English

确定C ++函数中的左值和右值

[英]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. 我正在写一个C ++类。 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. 虽然情况A和情况B调用相同的函数(重载运算符),但情况a用作左值,而情况b用作右值。

For some reason, I want to have the effect that if 0 is passed to a[5], delete the node 5 in core. 出于某种原因,我想要的是,如果将0传递给[5],则删除核心中的节点5。 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. 因此,我建议使用garbage int变量。 I declared the garbage as static because we need just one instance of this variable and we don't care its value. 我将garbage声明为静态因为我们只需要这个变量的一个实例而我们不关心它的值。

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. 您可以使用setter和getter轻松解决问题。 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. 就个人而言,我不使用它,我的地图包含在根本不提供operator[]中,而是有.get(key, default) .init(key) .setdefault(key, default) .init(key).setdefault(key, default)等等取决于班级。

// 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. 这应该工作,但5将总是给你一个垃圾结果。

You question is now clear, unfortunately you will have no way to do that is C++. 你的问题现在很清楚,遗憾的是你无法做到这一点就是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. operator[]不是getter和setter:它只能返回一个引用,并且该引用仅用于单独的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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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