前言:
今天我们对“我的世界映射键位设置在哪”大体比较关心,我们都需要学习一些“我的世界映射键位设置在哪”的相关内容。那么小编也在网络上搜集了一些关于“我的世界映射键位设置在哪””的相关内容,希望小伙伴们能喜欢,看官们一起来了解一下吧!高效地修改映射项的键
映射是一个关联容器,它存储键值对。容器按键排序。键必须是唯一的,并且它们是 const-qualified,因此它们不能被更改。
例如,如果我填充一个映射并尝试更改键,我会在编译时得到一个错误:
map<int, string> mymap { {1, "foo"}, {2, "bar"}, {3, "baz"}};auto it = mymap.begin();it->first = 47;
输出:
error: assignment of read-only member ... 5 | it->first = 47; | ~~~~~~~~~~^~~~
如果你需要重新排序映射容器,你可以通过使用 extract() 方法交换键来实现。
C++17 新增的 extract() 是映射类及其衍生类的成员函数。它允许从序列中提取映射的元素,而不影响有效载荷。一旦提取,键不再 const-qualified,可以被修改。
让我们看一个例子。
如何做到这一点…
在这个例子中,我们将定义一个映射,代表比赛中的参赛者。在比赛的某个时刻,顺序发生了变化,我们需要修改映射的键。
我们首先定义映射类型的别名:
using Racermap = map<unsigned int, string>;
这允许我们在代码中一致地使用类型。
我们将为打印映射编写一个函数:
void printm(const Racermap &m) { cout << "Rank:\n"; for (const auto& [rank, racer] : m) { cout << format("{}:{}\n", rank, racer); }}
我们可以在任何时候将映射传递给这个函数来打印出当前的排名。
在我们的 main() 函数中,我们定义了一个具有参赛者初始状态的映射:
int main() { Racermap racers { {1, "Mario"}, {2, "Luigi"}, {3, "Bowser"}, {4, "Peach"}, {5, "Donkey Kong Jr"} }; printm(racers); node_swap(racers, 3, 5); printm(racers);}
键是一个表示参赛者排名的 int。值是一个包含参赛者名称的字符串。
然后我们调用 printm() 打印当前排名。对 node_swap() 的调用将交换两个参赛者的键,然后我们再次打印。
在某个时刻,一个参赛者落后了,另一个参赛者抓住机会在排名中上升。node_swap() 函数将交换两个参赛者的排名:
template<typename M, typename K>bool node_swap(M & m, K k1, K k2) { auto node1{ m.extract(k1) }; auto node2{ m.extract(k2) }; if(node1.empty() || node2.empty()) { return false; } swap(node1.key(), node2.key()); m.insert(move(node1)); m.insert(move(node2)); return true;}
这个函数使用映射的 extract() 方法提取指定的元素。这些提取的元素称为节点。
节点是 C++17 开始的新概念。这允许从映射类型结构中提取元素,而不影响元素本身。节点被取消链接,返回节点句柄。一旦提取,节点句柄通过节点的 key() 函数提供对键的可写访问。然后我们可以交换键并将它们重新插入映射中,而无需复制或操作有效载荷。
当我们运行这段代码时,我们得到映射的打印输出,节点交换前后:
Rank:1:Mario2:Luigi3:Bowser4:Peach5:Donkey Kong JrRank:1:Mario2:Luigi3:Donkey Kong Jr4:Peach5:Bowser
这一切都是通过 extract() 方法和新的 node_handle 类实现的。让我们更仔细地看看这是如何工作的。
它是如何工作的…
这种技术使用了新的 extract() 函数,它返回一个 node_handle 对象。顾名思义,node_handle 是对节点的句柄,它由一个关联元素及其相关结构组成。extract 函数在保留节点位置的同时与其解关联,并返回一个 node_handle 对象。这有效地从关联容器中移除了节点,而没有触及数据本身。node_handle 允许你访问解关联的节点。
node_handle 有一个成员函数 key(),它返回对节点键的可写引用。这允许你在节点从容器中解关联时更改键。
还有更多…
使用 extract() 和 node_handle 时需要注意以下几点:
如果找不到键,extract() 函数将返回一个空的节点句柄。你可以使用 empty() 函数测试节点句柄是否为空:
auto node{ mapthing.extract(key) };if(node.empty()) { // node handle is empty}
extract() 函数有两个重载版本:
node_type extract(const key_type& x);node_type extract(const_iterator position);
我们使用了第一种形式,通过传递一个键。你也可以使用迭代器,这通常不需要查找。
请记住,你不能从字面量中获取引用,所以像 extract(1) 这样的调用通常会因为段错误而崩溃。
插入映射时键必须保持唯一。
例如,如果我尝试将一个键更改为映射中已经存在的值:
auto node_x{ racers.extract(racers.begin()) };node_x.key() = 5; // 5 is Donkey Kong Jrauto status = racers.insert(move(node_x));if(!status.inserted) { cout << format("insert failed, dup key: {}", status.position->second); exit(1);}
插入失败,我们得到了错误消息:
insert failed, dup key: Donkey Kong Jr
在这个例子中,我将 begin() 迭代器传递给 extract()。然后我将键分配了一个已经在使用中的值(5, Donkey Kong Jr)。插入失败,结果的状态 status.inserted 是 false。status.position 是找到的键的迭代器。在 if() 块中,我使用 format() 打印找到的键的值。
标签: #我的世界映射键位设置在哪