【问题标题】:C++ map assignment overload for different types不同类型的 C++ 映射分配重载
【发布时间】:2014-12-16 17:22:28
【问题描述】:

我有一个继承自 unordered_map 的自定义类,如下所示:

class _map : public unordered_map<string, _pointer> {
    public:
    // STUFF ...
};

假设_pointer 是另一个自定义类,它的作用是帮助我处理指针问题。 _pointers 可以由许多不同的预定义类型构造,例如:

vector<...> v;
_pointer p = _pointer(v);
// p is now a _pointer holding v and vector<...> data

现在,如果我想在我的地图上存储矢量<...>_pointers,我可以这样做:

_map map;
vector<...> v;
map["a_vector"] = _pointer(v);

它有效,但我希望能够这样做:

_map map;
vector<...> v;
map["a_vector"] = v;

并自动将其分配为_pointer(v),可能是通过重载map 分配内容的方式并通过调用特定的_pointer 构造函数来明确告诉它处理vector&lt;...&gt;

我已经尝试过这样做(通过重载 operator[]、operator=),但我似乎不会去某个地方。任何人都可以建议我实现这种行为的方法吗?

谢谢。

常见问题:

问:为什么在标识符名称上使用 _?你不知道这是不好的做法吗?
A:手头的问题没关系。

问:您的代码不是 RAII。
A:那么,什么?

问:为什么不使用 unique_ptr/smart_ptr?为什么要直接处理指针?
A:因为我需要,而且这对于手头的问题也没有关系。

问:为什么要重载 unordered_map?为什么不使用这个_OTHER_OPTION_?
A:不用了,谢谢,这是我需要做的。

【问题讨论】:

  • _pointer上定义一个隐式转换构造函数怎么样?
  • 谢谢@cdhowie,这听起来像是要走的路,但我不知道该怎么做。
  • 等等,如果地图的值类型是_pointer*,你怎么能做到map["a_vector"] = _pointer(v);?我们可以看到_pointer 的示例构造函数吗?
  • “你为什么要重载 unordered_map? - 你为什么不使用这个 OTHER_OPTION? - 不,谢谢,这就是我需要做的。”有人不得不说:公开从 stl 容器类派生的唯一有点理智的理由是写一个速写。
  • 是您的常见问题解答。从标准容器派生总是一个错误。

标签: c++ operator-overloading overloading unordered-map


【解决方案1】:

单独重载operator[] 并没有完全直接的方法。让我解释一下原因。

a 是具有重载operator[] 的类型时说a[b] = c; 相当于说a.operator[](b) = c;。请注意,操作员不知道c,也不知道它的类型。在典型的标准库容器中,operator[] 返回一个value_type &amp;。这允许赋值语法,因为引用是左值。您所做的只是为容器中已经存在的对象分配一个新值。

应该清楚为什么你不能合理地重载 operator[] 来做你想做的事:你不能根据返回值重载,这是各种 @987654330 的唯一方法 @ 重载会有所不同,因为大概它们都需要将 string 作为参数。

即使您尝试将运算符实现为template &lt;typename T&gt; T &amp; operator[](string key);,您仍然会遇到问题,因为类型推导不适用于返回类型。你必须写出a.operator[]&lt;decltype(c)&gt;(b) = c;,这太恶心了。

话虽如此,有一个选项有点老套,但可行:让您的operator[] 返回一个代理对象,类似于std::vector&lt;bool&gt;::operator[]() 采用的方法。代理类型需要:

  • operator _pointer *&amp;()(和operator _pointer *() const),以便它可以在需要_pointer * 的上下文中使用。 (这些是隐式转换运算符。)
  • proxy_type &amp; operator=(_pointer *) 以便可以直接分配新值。 (当c_pointer * 时,这将允许a[b] = c 在地图上工作。
  • 您想接受的任何其他类型的赋值运算符。如果您可以接受任何内容,那么例如template &lt;typename T&gt; proxy_type &amp; operator=(T const &amp;);。这将处理您当前尝试实施的案例。
  • 可能是_pointer * operator-&gt;()_pointer &amp; operator*(),如果您希望代理类型在取消引用时表现得像_pointer *

【讨论】:

    【解决方案2】:

    你的 _pointer 构造函数就足够了...... 如果你真的定义了一个

    #include <string>
    #include <map>
    #include <vector>
    using namespace std;
    
    class Foo{
        int _ent;
    public:
        Foo() : _ent(0) {}
        Foo(int ent) : _ent(ent) {}
        Foo(const vector<int>& ents) : _ent(ents.front()) {}
        void printEnt() const{cout << _ent << ' ';}
    };
    
    int main()
    {
        map<string, Foo> bar;
        vector<int> v{10, 20, 30, 40, 50};
    
        bar["blah"] = 13;
        bar["bleck"] = v;
    
        bar["blah"].printEnt(); // prints 13
        bar["bleck"].printEnt(); // prints 10
    
        return 0;
    }
    

    我怀疑问题在于您没有定义与您尝试分配的vector 匹配的构造函数。

    如果您尝试创建一个通用指针类,也就是 AKA C++ 的自动指针,您肯定想要模板化 _pointer

    【讨论】:

    • 谢谢,但是有没有办法通过重载地图操作符来做到这一点?因为,在调用该作业时我需要做一些其他的事情。
    • @almosnow 没有。地图的operator[] 将返回_pointer&amp;operator= 将在地图上的_pointer&amp; not 上执行。因此,更改地图的operator[] 不会改变任何事情。覆盖std::unordered_map::emplace 将控制要分配的键和值。 (应该知道,完全覆盖 std 容器是一个坏主意。但这并不是没有警告过你。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-09
    • 2019-05-02
    • 1970-01-01
    • 2021-04-24
    • 1970-01-01
    • 2023-03-25
    相关资源
    最近更新 更多