考虑对一个tuple的读取,如下代码:
int a;
char b;
double c;
std::tuple<int,char,double> 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<int, bool> 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<int, std::string> mymap{ {1,"hello"},{2," "},{3,"world"} };
std::map<int, std::string>::iterator ite_beg = mymap.begin();
std::map<int, std::string>::iterator ite_end = mymap.end();
for ( ; ite_beg != ite_end; ++ite_beg) {
std::pair<int, std::string>& pp = *ite_beg;
std::cout << pp.first << " " << pp.second << std::endl;
}
看着很高大上的,能蒙一下不懂技术的老板多掏钱给你。其实,这段代码很low,就是写个迭代器类型,拷贝粘贴就完成了。
C++11 引入auto后,可以不用迭代器的类型了,代码如下:
std::map<int, std::string> 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<int, std::string> mymap{ { 1,"hello" },{ 2," " },{ 3,"world" } };
for ( auto& pp : mymap) {
std::cout << pp.first << " " << pp.second << std::endl;
}
一切都很嗨,就是pp.first,pp.second很不爽,这时候,结构化绑定就来帮忙了。代码如下:
std::map<int, std::string> 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 <vector>
#include <string>
class Config_Base {
std::string name;
std::size_t id;
std::vector<std::string> 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 <vector>
#include <string>
#include <iostream>
class Config_Base {
std::string name="hello";
std::size_t id=123;
std::vector<std::string> 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 <std::size_t N>
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<Config>
: std::integral_constant<std::size_t, 3> {};
/*等价于
template<>
struct tuple_size<Config>{ static const int value = 3; };
*/
}
namespace std {
template<std::size_t N>
struct tuple_element<N, Config> {
using type = decltype(std::declval<Config>().get<N>());
};
/*等价于
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<std::string>&; };
*/
}
int main(){
Config cfg;
auto& [a,b,c] = cfg;
std::cout << a << std::endl;
}
结构化绑定易错陷阱,考虑如下代码:
1 #include <iostream>
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
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/269990
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!