Files
CPlusPlusThings/site_extras/modern-cpp-cpp17-structured-bindings.md
light-city dfe1c933b3 docs: address community issue feedback (#5 #338 #142 #246 #136 #303)
- const README: rewrite the space-saving claim per issue #5 follow-ups
  (constant-expression const vs #define immediates; which const qualify
  as constant expressions)
- const README: fix the class-section diagnosis per issue #338 (overload
  resolution picks the const overload; the restriction only surfaces
  once that overload is removed)
- sizeof README: virtual-inheritance result is compiler-dependent
  (GCC merges vbptr+vfptr -> 16, MSVC keeps them separate -> 32) #246
- static README: new section on internal linkage / access restriction
  with anonymous-namespace comparison #142
- 10-day practice: full problem list table + fixed day links #136
- new design_pattern/singleton/singleton_default.hpp: reusable
  thread-safe CRTP singleton template, compile+concurrency tested #303
2026-10-13 19:23:54 +08:00

117 lines
2.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
> 来自 [C++那些事网站](https://light-city.github.io/stories_things/modern-cpp/cpp17/structured-bindings/) 的文章,由站点同步脚本导出。
# C++17 结构化绑定
在聊结构化绑定之前,有几个面试问题,看看你会不会?
- 如何使用结构化绑定访问自定义类的私有成员?
- 如何使用结构化绑定修改自定义类的成员呢?
这几个题目估计没几个人能答上来,题目与答案网上也都没有,基于这些问题,我们引出本文的内容:如何为自定义类型支持结构化绑定,里面有哪些坑?
**注:懒人版,答案与代码已放星球。**
为了让本文的内容更加丝滑,从示例出发。
## 1.自定义类型
如果给定一个类:
```cpp
struct Foo {
Foo(int64_t id, std::string data) : id_(id), data_(std::move(data)) {}
void Print() { std::cout << "id = " << id_ << ", data = " << data_ << std::endl; }
private:
int64_t id_;
std::string data_;
};
```
要让下面这个代码运行起来:
```cpp
int main() {
Foo f{12, "hello world"};
const auto& [id, data] = f;
std::cout << "id = " << id << ", data = " << data << std::endl;
f.Print();
}
```
如果直接运行会编译:
```cpp
cannot decompose inaccessible member 'Foo::id_' of 'const Foo'
42 | const auto& [id, data] = f;
```
那么怎么做呢?
## 2.支持结构化绑定
这个问题我们使用两个步骤:
1.特化 `std::tuple_size` 和 `std::tuple_element`
```cpp
namespace std {
template <>
struct tuple_size<Foo> : std::integral_constant<std::size_t, 2> {};
template <>
struct tuple_element<0, Foo> {
using type = int64_t;
};
template <>
struct tuple_element<1, Foo> {
using type = std::string;
};
}
```
2.为上面的结构体添加友元get函数,然后实现即可:
```cpp
template <std::size_t Index>
decltype(auto) get(const Foo& f);
template <>
decltype(auto) get<0>(const Foo& f) {
return f.id_;
}
template <>
decltype(auto) get<1>(const Foo& f) {
return f.data_;
}
```
此时便可以正常的工作了,得到输出:
```cpp
id = 12, data = hello world
id = 12, data = hello world
```
最后,抛出几个问题:
- 上面提供的是只读访问,如果在访问的时候修改const auto &会发生什么?
例如:
```cpp
auto& [id, data] = f;
```
- 如何支持对类成员的修改访问?
即,让这个语句能够正常运行
```cpp
auto& [id, data] = f;
```
好了,本节完,欢迎留言区交流。