c++ - 重写映射迭代器以返回dynamic_casted值

标签 c++ boost c++17

编辑:我现在有一个可行的解决方案,https://wandbox.org/permlink/joS14MzfmmayNRd3 ,只是想知道是否可以改进。

我有一张 map map<int, unique_ptr<Base>> ,其值也可以是 unique_ptr<Derived> 类型。我有包装类 A 和 B,它们分别在映射中存储 Base 和 Derived(所有 Base 或所有 Derived 实例)。

我想为 A 和 B 引入映射语义(引用绑定(bind)),其工作原理如下:

// a is of type A, all values in map are of type Base
for (auto& [k, v] : a) {
  // v should be of type Base&
} 

// b is of type B, all values in map are type Derived
for (auto& [k, v] : b) { 
  // v should be of type Derived&
  // can call functions that are in Derived but not in Base
} 

我发现boost的transform_iterator和iterator_adaptor可能很有用(如果有一种方法可以在没有boost的情况下做到这一点那就更好了),但我似乎没有正确使用它们。这样做的正确方法是什么?

#include <memory>
#include <boost/iterator/transform_iterator.hpp>
#include <vector>
#include <unordered_map>
#include <iostream>

using namespace std;

class Base {
    public:
        Base(int k) : i(k) {}
        virtual ~Base() {}
        
        virtual int getV() {
            return i;
        }
        
        int i = 0;
};

class Derived : public Base {
    public:
        Derived(int k) : Base(k) {}
        
        int getV() override {
            return j - i;
        }

        void setV(int p) {
            i = p;
        }
        
        int j = 0;
};

typedef unordered_map<int, unique_ptr<Base>> BaseMap;

class A {
    public:
        A(vector<int> keys) {
            for (auto& k : keys) {
                m.emplace(k, make_unique<Base>(k));
            }
        }
        
        class Converter {
            public:
                explicit Converter() {}

                pair<BaseMap::key_type, reference_wrapper<Base>> operator()(BaseMap::value_type& p) const {
                    return {p.first, *p.second};
                }
        };

        using MyIterator = boost::transform_iterator<Converter, typename BaseMap::iterator>;

        MyIterator begin() {
            return MyIterator(m.begin());
        }
        
        MyIterator end() {
            return MyIterator(m.end());
        }
       
        protected:
            BaseMap m;
};

class B : public A {
    public:
        B(vector<int> keys) : A(keys) {
            m.clear(); // demo only, since we have to init A
            for (auto& k : keys) {
                m.emplace(k, make_unique<Derived>(k));
            }
        }

        class Converter {
            public:
                explicit Converter() {}

                pair<BaseMap::key_type, reference_wrapper<Derived>> operator()(BaseMap::value_type& p) const {
                    return {p.first, dynamic_cast<Derived&>(*p.second)};
                }
        };
        
        using MyIterator = boost::transform_iterator<Converter, typename BaseMap::iterator>;
        
        MyIterator begin() {
            return MyIterator(m.begin());
        }
        
        MyIterator end() {
            return MyIterator(m.end());
        }
};

int main ()
{
    A a({1,2,3,4});
    B b({1,2,3,4});
    
    for (auto [k, v] : a) {
        cout << v.get().getV() << " ";
    }
    cout << endl;
    
    for (auto [k, v] : b) {
        cout << v.get().getV() << " ";
        v.get().setV(42);
    }
    
    cout << endl << "after setV:\n";
    
    for (auto [k, v] : b) {
        cout << v.get().getV() << " ";
    }
    
    return 0;
}

最佳答案

这里有几个问题:

  1. 您正在使用p按值(value)计算,也就是说,您正在制作拷贝。但是std::unique_ptr不可复制。
  2. BaseMap::value_type已经是std::pair<const Key, Value> .
  3. std::make_pair()衰减参数,您需要将参数包装到 std::reference_wrapper 中与 std::ref()传递引用。
class Converter {
public:
    std::pair<BaseMap::key_type, Derived&> operator()(BaseMap::value_type& p) const {
        return std::make_pair(p.first, std::ref(dynamic_cast<Derived&>(*p.second)));
    }
};

之后,基于范围的 for应该看起来像这样:

for (auto [k, v] : b) {
    std::cout << v.get();
}

请注意decltype(v)Derived& , not Derived .

(此答案是在编辑问题中的代码之前编写的。)

关于c++ - 重写映射迭代器以返回dynamic_casted值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68012876/

相关文章:

c++ - 使用 boost 的多维固定大小数组

c++ - 尝试使用 boost asio PUT 时出现 Amazon S3 403 错误

c++ - Boost IOStream 创建 zip 文件的示例?

linux - 在 Fedora 17 上安装 Boost.Log

c++ - 处理 std::variant 中的循环依赖

c++ - 这被认为是动态内存分配吗?

C++ 段错误(核心已转储)

c++ - 模板模板参数的替换失败

c++ - 从字符串中提取字符时,基于范围的循环和stringstream有什么区别

c++ - 如何使用现有的 Qt 5.1.1 安装 Qt 4.8.4