首页 文章

C类打字课

提问于
浏览
1

我正在编写一些包含std :: unordered_map类型的C代码,我希望隐藏底层类型并将其作为另一种类型呈现 . 更具体地说,我想用std :: unordered_map用另一种类型包装std :: pair . 为了论证,让我们假设包装器看起来像这样......

template <typename ActualT >
class wrapper final
{
private:
    ActualT actual_;
public:
    //Some constructors...
    typename ActualT::first_type & get_first()
    {
        return actual_.first;
    }
    typename ActualT::second_type & get_second()
    {
        return actual_.second;
    }
};

我的理由是,由于包装类只有一个成员,它是包装的确切类型,将引用从原始类型转换为包装类型应该没问题,但结构的类型兼容性表明成员应具有要兼容的类型的相同类型和名称 . 以这种方式使用类型惩罚可能会导致未定义的行为或对齐问题吗?

using my_map = std::unordered_map < int, int >;
my_map m;
//Do some inserts...
reinterpret_cast<wrapper<typename my_map::value_type>&>(*m.find(10)).get_second() = 1.0;

我希望允许客户端代码访问 Map 的条目,而不知道 Map 返回的对 . 我还想编写一个自定义的前向迭代器,因此我需要返回对该条目的引用 . 将对该引用的引用转换为对作为包装器的类的引用会被认为是危险的吗?

是否有更好的方法来实现这一目标?

2 回答

  • 2

    这绝对是未定义的行为 .

    认真重新考虑你的优先事项 .

    表格的一些免费功能

    const my_map::key_type & MeaningfulNameHere(my_map::reference)
    

    将为你提供有意义的名字 .

    如果必须使用不同的名称包装标准库,只需使用非显式构造函数,并存储引用 .

    template <typename Map>
    class entry final
    {
    private:
        typename Map::reference ref;
    public:
        entry(Map::reference ref) : ref(ref) {}
    
        const typename Map::key_type & key()
        {
            return ref.first;
        }
        typename Map::mapped_type & value()
        {
            return ref.second;
        }
    };
    

    如果你真的需要迭代器去取消引用 entry 你可以 . 但是你可以隐式地从 Map::iterator::operator* 返回的 Map::reference 实例化 entry ,你不需要自定义迭代器 .

    template <typename Map>
    class entry_iterator
    {
    private:
        typename Map::iterator it;
        entry<Map> entry;
    public:
        entry<Map>& operator*() { return entry; }
        entry_iterator operator++() { ++it; entry = *it; return *this; }
        // etc
    }
    
  • 2

    所以你可以清理它,但我不建议:

    #include <unordered_map>
    #include <iostream>
    using namespace std;
    
    template <class Key, class Value>
    class wrapper
    {
    public:
       explicit wrapper(std::pair<const Key, Value>& kvp)
          : _key{kvp.first}
          , _value{kvp.second}
       {}
    
       const Key& key() const { return _key; }
       Value& value()         { return _value; }
    
    private:
       const Key& _key;
       Value& _value;
    };
    
    int main()
    {
       unordered_map<int,int> m;
    
       m[1] = 1;
       m[3] = 3;
    
       auto it = m.find(1);
    
       wrapper w{*it};
       w.value() = 30;
    
       std::cout << w.key() << " -> " << w.value() << '\n';
    }
    

    以上内容有效地隐藏了您 class 用户的 pair . 它不处理异常(例如 find() 返回 end() ),并且不保证生命周期 . 's marginally better than what you have because it doesn' t要求 reinterpret_cast 为不相关的类型 .

    然而, mapunordered_mapset 等将返回迭代器存储为对只是库的一部分 - 它's the canonical form and I don' t看到了屏蔽人们的好处 .

相关问题