【问题标题】:How to iterate a class that overload the operator[]? [duplicate]如何迭代一个重载 operator[] 的类? [复制]
【发布时间】:2019-03-23 01:28:29
【问题描述】:

我有这样的课:

class C {
private:
    std::unordered_map<char, int> m = {{'a', 1}, {'b', 2}, {'c', 3}};

public:
    int operator[](const char& key) const {
        return m.find(key)->second;
    }
};

是否可以在不修改类的情况下迭代map的元素?

我想要类似的东西:

for (auto x: c) {
    // x -> a map element
}

【问题讨论】:

  • 您必须提供begin(c)end(c)。不修改类似乎很难。
  • 几乎,但没有。无法检索m 的迭代器,也无法检索其键列表,因此无法实现begin/end 对。
  • 看来我需要修改类,或者以某种方式找到密钥,对吧?

标签: c++


【解决方案1】:

没有。

除了 ranged-for 专门施加的约束(其他人已经介绍过)之外,您的类没有公开任何方法来知道地图中的哪些元素,甚至不包括第一个或最后一个元素键。它不公开任何迭代器。它根本没有暴露足够的信息来执行迭代。

【讨论】:

    【解决方案2】:

    不,ranged-for 循环不使用 operator[]

    定义

    for ( range_declaration : range_expression ) loop_statement
    

    是不是被当成是(不引入__names

    {
        auto && __range = range_expression ; 
        auto __begin = begin_expr ;
        auto __end = end_expr ;
        for ( ; __begin != __end; ++__begin) {   
            range_declaration = *__begin; 
            loop_statement    
        } 
    } 
    

    对于begin_exprend_expr 有以下规则:

    • 如果range_expression是数组类型的表达式,那么begin_expr__rangeend_expr(__range + __bound), 其中__bound 是数组中的元素数(如果数组 大小未知或类型不完整,程序是 格式错误)
    • 如果 range_expression 是类类型 C 的表达式,它同时具有名为 begin 的成员和名为 end 的成员(无论 此类成员的类型或可访问性),然后 begin_expr__range.begin()end_expr__range.end();
    • 否则,begin_exprbegin(__range)end_exprend(__range),通过参数相关查找(非 ADL 不执行查找)。

    对你的类做一个简单的改变就足够了,添加beginend,委托给m.begin()m.end()

    class C {
    private:
        std::unordered_map<char, int> m = {{'a', 1}, {'b', 2}, {'c', 3}};
    
    public:
        int operator[](const char& key) const {
            return m.find(key)->second; 
            // return m.at(key); or return m[key]; are both safer than this
        }
        std::unordered_map<char, int>::iterator begin() {
            return m.begin();
        }
        // overloaded on the constness of "this"
        std::unordered_map<char, int>::const_iterator begin() const {
            return m.begin();
        }
        std::unordered_map<char, int>::iterator end() {
            return m.end();
        }   
        // overloaded on the constness of "this"
        std::unordered_map<char, int>::const_iterator end() const {
            return m.end();
        }   
    };
    

    【讨论】:

    • const 带有const_iterator 的版本可能也不错。
    • 根据类的使用方式,仅提供 const 迭代器以封装对地图的更改可能是有意义的。
    • 添加noexcept 可能会更好。
    • cbegin/cend?
    • @Caleth 但是你不会只为一种语言结构设计界面
    【解决方案3】:

    如果一个类提供迭代器,即如果begin(c)end(c) 返回迭代器(或c.begin()c.end()),则它可以被迭代。您的类不提供迭代器,并且不可能在类之外实现迭代器,因为内部映射是私有的。

    所以,答案是否定的,类确实需要修改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-14
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      • 2020-12-04
      • 2015-07-09
      相关资源
      最近更新 更多