我怎样才能 return `map<K, V>::iterator`? (`map` class 扩展了 `std::map`)

How can I return `map<K, V>::iterator`? (`map` class extends `std::map`)

我正在制作扩展 std::map 的自定义地图 class (kc::map),我想添加 at_index(),我需要 return map<K, V>::iterator。但是当我returnmap<K, V>的时候出现这个错误:error: invalid use of incomplete type ‘class kc::map<K, V>’:

namespace kc
{
    template<typename K, typename V> class map : public std::map<K, V>
    {
        public:
            using std::map<K, V>::map;
            map<K, V> get_value()
            {
                return *this;
            }
            map<K, V>::iterator at_index(int index)
            {
                map<K, V> m = get_value();
                for (int i = 0; i < index; i++)
                {
                    m.erase(m.begin());
                }
                return m.begin();
            }
    };
};

你可以 return 一个 std::map<K,V>::iterator。这将使您的代码编译,但迭代器将无效。 get_value returns 副本,mat_index 的本地副本,并在函数 returns.

时被销毁

从标准容器公开继承很少是个好主意。标准容器不是用来继承的(例如,它们没有虚拟析构函数)。你可以把at_index写成一个算法:

#include <map>
#include <iostream>

template <typename IT>
IT get_at_index(IT begin,IT end,unsigned index){
    if (std::distance(begin,end) < index) return end;
    return std::next(begin,index);
}


int main() {
    std::map<int,int> m{{1,1},{2,2},{3,3}};
    auto it = get_at_index(m.begin(),m.end(),1);
    if (it != m.end()) std::cout << it->first << " " << it->second << "\n";

    it = get_at_index(m.begin(),m.end(),5);
    if (it == m.end()) std::cout << "index 5 is out of range\n";
} 

但是,std::map 并不意味着可以通过索引访问。推进地图迭代器是相当昂贵的。如果您想要一个可以通过索引访问的键值对容器,请考虑使用 std::vector<std::pair<K,V>>

忽略代码的真正问题(不推荐从标准容器派生,at_index returns 到本地对象的悬空迭代器 m)来编译代码你有两个选择。

  1. 在 class 中,您不需要在 class 的成员前面加上 class 名称。由于 iterator 不是 class 成员,您需要先添加它,然后不合格的 iterator 才会起作用:
using iterator = typename std::map<K, V>::iterator;
iterator at_index(int index)
  1. 你可以直接使用std::map::iterator:
typename std::map<K, V>::iterator at_index(int index)

如果您实际上想做的是获取 std::map 中的第 i 个项目,这将有效:

#include <map>
#include <stdexcept>
#include <iostream>

namespace kc
{
    template<typename K, typename V> class map
    {
        private:
            std::map<K, V> impl;

        public:
            using iterator = typename std::map<K, V>::iterator;
            using value_type = typename std::map<K, V>::value_type;

            std::pair<iterator, bool> insert( const value_type& value )
            {
                return impl.insert(value);
            }
           
            iterator at_index(int index)
            {
                if (index >= impl.size())
                {
                    throw std::invalid_argument("index out of range");
                }
                auto it = impl.begin();
                std::advance(it, index);
                return it;
            }
    };
};

int main()
{
    kc::map<int, int> m;
    m.insert({1, 1});
    m.insert({2, 2});
    m.insert({3, 3});
    std::cout << m.at_index(2)->second;
}