博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ structured binding
阅读量:6071 次
发布时间:2019-06-20

本文共 4137 字,大约阅读时间需要 13 分钟。

考虑对一个tuple的读取,如下代码:

int a;char b;double c;std::tuple
tp = std::make_tuple(1, 'a', 2.3);a = std::get<0>(tp); b = std::get<1>(tp);c = std::get<2>(tp);

如果你认为tuple用处没有pair大,则有pair的代码:

int x;bool y;std::pair
pp = std::make_pair(100,true);x = pp.first; x = std::get<0>(pp);y = pp.second;y = std::get<1>(pp);

C++11给出了简洁的方式,如下代码:

int x;bool y;std::tie(x,y) = std::make_pair(100,true);

C++17给出更简洁的方式,如下代码:

auto[x,y] = std::make_pair(100,true);

这就是结构化的绑定(SB)的第二种形式。SB可以绑定数组的元素(第一种形式),SB绑定结构体的数据成员(第三种形式)。

有啥用呢?就是简化代码!方便程序员写代码。

考虑最早的循环遍历一个map,代码如下:

std::map
mymap{ {
1,"hello"},{
2," "},{
3,"world"} };std::map
::iterator ite_beg = mymap.begin();std::map
::iterator ite_end = mymap.end();for ( ; ite_beg != ite_end; ++ite_beg) { std::pair
& pp = *ite_beg; std::cout << pp.first << " " << pp.second << std::endl;}

看着很高大上的,能蒙一下不懂技术的老板多掏钱给你。其实,这段代码很low,就是写个迭代器类型,拷贝粘贴就完成了。

C++11 引入auto后,可以不用迭代器的类型了,代码如下:

std::map
mymap{ { 1,"hello" },{ 2," " },{ 3,"world" } };auto ite_beg = mymap.begin();auto ite_end = mymap.end();for (; ite_beg != ite_end; ++ite_beg) { auto& pp = *ite_beg; std::cout << pp.first << " " << pp.second << std::endl;}

C++11引入新式的for循环语法后,可以让编译器替你展开这种繁文缛节的定式代码。

std::map
mymap{ { 1,"hello" },{ 2," " },{ 3,"world" } };for ( auto& pp : mymap) { std::cout << pp.first << " " << pp.second << std::endl;}

一切都很嗨,就是pp.first,pp.second很不爽,这时候,结构化绑定就来帮忙了。代码如下:

std::map
mymap{ { 1,"hello" },{ 2," " },{ 3,"world" } };for ( auto& pp : mymap) { auto[a,b] = pp; std::cout << a << " " << b << std::endl;}

C++17看来,pp也是很多余的,进一步简化代码如下:

for ( auto[a,b] : mymap) {    std::cout << a << " " << b << std::endl;}

结构化绑定支持自定义类,但是需要自定义类暴露公有成员。考虑一个有继承的情况:

#include 
#include
class Config_Base { std::string name; std::size_t id; std::vector
data;public: auto get_name(){ return std::string_view(name); } auto get_id(){ return id; } auto get_data(){ return (data); }};class Config : private Config_Base{};int main(){ Config cfg; auto& [a,b,c] = cfg; //编译失败,原因:私有成员看不到呀。}

我们需要改造一下,骗过编译器。让我们的自定义类的行为好像是tuple一般。怎么骗呢?代码如下:

#include 
#include
#include
class Config_Base { std::string name="hello"; std::size_t id=123; std::vector
data;public: auto get_name() const{ return std::string_view(name); } auto get_id() const{ return id; } auto get_data() const{ return (data); //括起来,就是返回引用,很神奇。 }};class Config : private Config_Base{ //...public: template
decltype(auto) get() const { if constexpr (N == 0) return get_name(); else if constexpr (N == 1) return get_id(); else if constexpr (N == 2) return get_data(); }};namespace std { template<> struct tuple_size
: std::integral_constant
{}; /*等价于 template<> struct tuple_size
{ static const int value = 3; }; */}namespace std { template
struct tuple_element
{ using type = decltype(std::declval
().get
()); }; /*等价于 template<> struct tuple_element<0,Config> { using type = std::string_view; }; template<> struct tuple_element<1,Config> { using type = std::size_t; }; template<> struct tuple_element<2,Config> { using type = const std::vector
&; }; */}int main(){ Config cfg; auto& [a,b,c] = cfg; std::cout << a << std::endl;}
结构化绑定易错陷阱,考虑如下代码:
1 #include 
2 3 struct S { 4 int i = 0; 5 ~S(){ std::cout << "~S() i=" << i << std::endl; } 6 }; 7 8 S makeS(){ 9 S s;10 return s; 11 }12 13 int main()14 {15 auto& [ d ] = makeS();16 d++;17 }

第15行编译失败。用伪代码展开,可以看到:

1 auto & __tmp = makeS();2 int& d = __tmp.i;

第1行的auto&是程序员输入的,显然是错误的。因为左值引用不能抓右值。

第2行的int&是编译器设定的(也是语言规范要求的),i是对__tmp.i的引用。

参考: https://github.com/tvaneerd/cpp17_in_TTs/blob/master/ALL_IN_ONE.md
https://blog.tartanllama.xyz/structured-bindings/

 

 

转载于:https://www.cnblogs.com/thomas76/p/8522639.html

你可能感兴趣的文章
iOS开发流程总结
查看>>
hadoop datanode 启动出错
查看>>
js颜色拾取器
查看>>
IDEA使用(1)intellIJ idea 配置 svn
查看>>
Thread Safety in Java(java中的线程安全)
查看>>
WPF 降低.net framework到4.0
查看>>
数据管理DMS 全量SQL诊断:你的SQL是健康的蓝色,还是危险的红色?
查看>>
搭建一个通用的脚手架
查看>>
开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
查看>>
开源磁盘加密软件VeraCrypt教程
查看>>
本地vs云:大数据厮杀的最终幸存者会是谁?
查看>>
阿里云公共镜像、自定义镜像、共享镜像和镜像市场的区别 ...
查看>>
shadowtunnel v1.7 发布:新增上级负载均衡支持独立密码
查看>>
Java线程:什么是线程
查看>>
mysql5.7 创建一个超级管理员
查看>>
【框架整合】Maven-SpringMVC3.X+Spring3.X+MyBatis3-日志、JSON解析、表关联查询等均已配置好...
查看>>
要想成为高级Java程序员需要具备哪些知识呢?
查看>>
带着问题去学习--Nginx配置解析(一)
查看>>
onix-文件系统
查看>>
java.io.Serializable浅析
查看>>