C++11 中 std::piecewise_construct 的使用

C++11 中 std::piecewise_construct 的使用「这是我参与11月更文挑战的第 10 天,活动详情查看:2021最后一次更文挑战」。 参加该活动的第 22 篇文章 前文 C++11 中的 emplace 存在的意义与注意事项 中提到过 map 在使

「这是我参与11月更文挑战的第 10 天,活动详情查看:2021最后一次更文挑战」。

参加该活动的第 22 篇文章

前文 C++11 中的 emplace 存在的意义与注意事项 中提到过 map 在使用 emplace 的时候需要注意一点,现在让我们回顾一下:

值得注意的是 map 类型的 emplace 处理比较特殊,因为和其他的容器不同,mapemplace 方法把它接收到的所有的参数都一起转发给 pair 的构造函数。但是对于一个 pair 来说,它既需要构造它的 key 又需要构造它的 value。如果我们按照之前普通的语法使用变参模板的话,则它是无法区分哪些参数用来构造 key, 哪些用来构造 value的。 比如下面的代码

// @note 无法区分哪个参数用来构造 key 哪些用来构造 value
// 有可能是 std::string s("hello", 1), std::complex<double> cpx(2) 
// 也有可能是 std::string s("hello"), std::complex<double> cpx(1, 2)
std::map<std::string, std::complex<double>> scp;
scp.emplace("hello", 1, 2); 

那我们该如何解决以上的这个问题呢? 首先,我们想到的是可以接受异构、变长参数的 tuple 来对参数进行分组。

我们将代码改成如下形式

std::pair<std::string, std::complex<double>> scp(
        std::make_tuple("hello"),
        std::make_tuple(1, 2));

可是这种语法还是编译无法通过。

image.png

image.png

这是因为这里还是有问题,两个 tuple 找不到正确的构造函数。

这个时候就需要使用 C++11 为我们提供的一个特殊类型 piecewise_construct_t 来帮助它们找到各自正确的构造函数了。

std::piecewise_construct_t 是一个空类,全局变量 std::piecewise_construct 就是该类型的一个变量。

则代码可以修改为如下

std::pair<std::string, std::complex<double>> scp(
    std::piecewise_construct, 
    std::make_tuple("hello"), 
    std::make_tuple(1, 2));

std::piecewise_construct —— 此常量值作为构造 pair 对象的第一个参数传递,以选择构造函数形式,通过将两个元组对象的元素转发给它们各自的构造函数来构造其成员。

调试结果如下

image.png

可见,这两个元组已经分别存在了 pairfirstsecond 的位置了【即第一个 tuple 作为 key,第二个 tuple 作为 value】

然后我们回到 map 中的 emplace 操作

因为 emplace 会把参数完美转发给 pair 进行构造,所以保证一致性,你需要使用同样的语法来完成 emplace 的调用,使用 forward_as_tuple 替代 make_tuple,该函数会帮你构造一个 tuple 并转发给 pair

具体代码如下所示

std::map<std::string, std::complex<double>> scp;
scp.emplace(std::piecewise_construct, ///< 此常量值作为构造 pair 对象的第一个参数传递,以选择构造函数形式,通过将两个元组对象的元素转发给它们各自的构造函数来构造其成员。
    std::forward_as_tuple("hello"), ///< 该函数会帮你构造一个 tuple 并转发给 pair 构造,并存储在 first 字段
    std::forward_as_tuple(1, 2)); ///< 该函数会帮你构造一个 tuple 并转发给 pair 构造,存储在 second 字段

std::cout << scp["hello"] << std::endl;

所以,想对于 map 避免临时变量的构造的话,你就需要构建两个 tuple 【增加了很多麻烦的步骤】。 至于这些操作是否值得,需要代码编写者自己考虑,从性能和代码优雅性、可读性上进行权衡。

所以,个人认为对于临时变量构建代价不是很大的对象(比如基础类型)建议使用 insert 而不是 emplace,毕竟写法简介、通俗易懂。

scp.insert({"world", {1, 2}});

今天的文章C++11 中 std::piecewise_construct 的使用分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/22982.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注