简体   繁体   English

如何在嵌套的 map 和 c++17 中使用 emplace/insert_or_assign?

[英]How to use emplace/insert_or_assign in nested map with c++17?

If I have如果我有

map<int, map<int, int>> m;

And when I need to insert, I could use当我需要插入时,我可以使用

m[1] = { {1, 1} };

But now I want to use emplace/insert_or_assign to replace it, I may use但是现在我想用 emplace/insert_or_assign 来代替它,我可能会用

m.emplace(1, map<int, int>{ {1, 1} });

But I think it is a bit complex to write, expecially I should write map<int, int> again, even more if the original map change into such as map<int, map<int, map<int, map<int, int>>>> , then I should repeat map<int, int> as much as it need.但是我觉得写起来有点复杂,特别是我应该重新写map<int, int> ,如果原来的map改成比如map<int, map<int, map<int, map<int, int>>>>就更map<int, map<int, map<int, map<int, int>>>> ,那么我应该根据需要重复map<int, int> So is there any more simple and readable method?那么有没有更简单易读的方法呢?

The question should be why do you want to use emplace / insert_or_assign at the first point.问题应该是为什么要在第一点使用emplace / insert_or_assign


The point of emplace is so that you don't do unnecessary creation until it is needed. emplace点是为了让您在需要之前不要进行不必要的创建。 With a map<int, map<int, int>> , you might want to create the inner map only if you are going to insert the new map. To properly utilize such behavior, you should only supply the arguments that construct the map, not the map itself.使用map<int, map<int, int>> ,您可能只想在要插入新的 map 时才创建内部 map。要正确利用这种行为,您应该只提供构建 map 的 arguments,不是 map 本身。

However, the only constructor map has that can also fill the container during construction is the one taking an initializer_list .但是,唯一的构造函数map也可以在构造过程中填充容器是采用initializer_list的构造函数。 So ideally you would want to write something like:所以理想情况下你会想写这样的东西:

m.emplace(1, {{1, 1}}) // this won't work

However, this wouldn't work because there's no way for emplace to deduce {{1, 1}} as a initializer_list .但是,这是行不通的,因为emplace无法将{{1, 1}}推断为initializer_list Which means you have to specify that manually like:这意味着您必须手动指定,例如:

m.emplace(1, std::initializer_list<std::pair<const int, int>>{{1, 1}})

That's quite some writing, which will only be worse if you have more nested layers.这是相当多的写作,如果你有更多的嵌套层,那只会更糟。 At this point it's probably better to just write:在这一点上,最好只写:

if (m.find(1) == m.end()) {
// or `!m.contains(1)` for C++20 or later
    m[1] = {{1, 1}};
}

On the other hand, if you didn't really care about the unnecessary construction, you should just use insert instead:另一方面,如果你真的不关心不必要的构造,你应该只使用insert代替:

m.insert({1, {{1, 1}}})

The point of insert_or_assign is to make map works on types that is not default constructible. insert_or_assign的要点是使 map 适用于不可默认构造的类型。

When you just call m[1] , this will default construct an object if m[1] does not exist.当您只调用m[1]时,如果m[1]不存在,这将默认构造一个 object。 However, that also means operator[] does not work if the type is not default constructible.但是,这也意味着如果类型不是默认可构造的,则operator[]不起作用。

However, since a map is default constructible, there isn't much difference between using operator[] directly and using insert_or_assign .但是,由于map是默认可构造的,因此直接使用operator[]与使用insert_or_assign之间没有太大区别。 So instead, just go use operator[] .因此,只有 go 使用operator[]

You could do你可以做

typedef map<int, int> mp;

and then do然后做

m.emplace(1, mp{ {1, 1} });

That's less verbose and also clearly indicates what is map constructor and what isn't.这不那么冗长,也清楚地表明什么是 map 构造函数,什么不是。

Hope this helps.希望这可以帮助。

Edit : You can also try doing编辑:您也可以尝试做

template <typename T>
using nest_mp = std::map<int, T>;

typedef std::map<int, int> mp;

and do并做

m.emplace(1, nest_mp<nest_mp<mp>>>{ {1, { {1, { {1, 1} } } } } };

There are two { braces for each map construction - one to invoke the std::map initializer list constructor, the other to invoke the std::pair initializer list constructor.每个 map 构造都有两个{大括号 - 一个调用std::map初始化列表构造函数,另一个调用std::pair初始化列表构造函数。

It'd be better not to use map<int, map<int, int>> at all.最好根本不要使用map<int, map<int, int>> Instead, use map<std::pair<int, int>, int .相反,使用map<std::pair<int, int>, int This means you have a composite key, so instead of storing a value at [A][B] you store it at [pair(A, B)] .这意味着你有一个组合键,所以不是将值存储在[A][B]中,而是将它存储在[pair(A, B)]中。 This way when you store a value it's always a single memory allocation for its node (because there's just one map).这样,当您存储一个值时,它总是为其节点分配一个 memory 分配(因为只有一个映射)。

Then you write code like this:然后你写这样的代码:

m.emplace(std::make_pair(1, 1), 1);
m.insert_or_assign({1, 1}, 1);

And if you want to iterate the values with a specific "first" integer in the key:如果你想用键中的特定“第一个”integer 迭代值:

int subkey = 1;
for (auto it = m.lower_bound({subkey, 0}),
    end = m.upper_bound({subkey, INT_MAX});
    it != end; ++it)
{
    // do something with elements whose key.first == subkey
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM