mirror of
https://github.com/changkun/modern-cpp-tutorial.git
synced 2025-12-17 20:54:39 +03:00
update: move std::variant to container chapter
This commit is contained in:
@@ -228,22 +228,27 @@ int index = 1;
|
|||||||
std::get<index>(t);
|
std::get<index>(t);
|
||||||
```
|
```
|
||||||
|
|
||||||
那么要怎么处理?答案是,**标准库做不到**。这里介绍一个使用 `boost::variant` 配合变长模板参数的黑魔法:
|
那么要怎么处理?答案是,使用 `std::variant<>`(C++ 17 引入),提供给 `variant<>` 的类型模板参数
|
||||||
|
可以让一个 `variant<>` 从而容纳提供的几种类型的变量(在其他语言,例如 Python/JavaScript 等,表现为动态类型):
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include <boost/variant.hpp>
|
#include <variant>
|
||||||
template <size_t n, typename... T>
|
template <size_t n, typename... T>
|
||||||
boost::variant<T...> _tuple_index(size_t i, const std::tuple<T...>& tpl) {
|
constexpr std::variant<T...> _tuple_index(const std::tuple<T...>& tpl, size_t i) {
|
||||||
if (i == n)
|
if constexpr (n >= sizeof...(T))
|
||||||
return std::get<n>(tpl);
|
|
||||||
else if (n == sizeof...(T) - 1)
|
|
||||||
throw std::out_of_range("越界.");
|
throw std::out_of_range("越界.");
|
||||||
else
|
if (i == n)
|
||||||
return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(i, tpl);
|
return std::variant<T...>{ std::in_place_index<n>, std::get<n>(tpl) };
|
||||||
|
return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(tpl, i);
|
||||||
}
|
}
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
boost::variant<T...> tuple_index(size_t i, const std::tuple<T...>& tpl) {
|
constexpr std::variant<T...> tuple_index(const std::tuple<T...>& tpl, size_t i) {
|
||||||
return _tuple_index<0>(i, tpl);
|
return _tuple_index<0>(tpl, i);
|
||||||
|
}
|
||||||
|
template <typename T0, typename ... Ts>
|
||||||
|
std::ostream & operator<< (std::ostream & s, std::variant<T0, Ts...> const & v) {
|
||||||
|
std::visit([&](auto && x){ s << x;}, v);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -251,7 +256,7 @@ boost::variant<T...> tuple_index(size_t i, const std::tuple<T...>& tpl) {
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
int i = 1;
|
int i = 1;
|
||||||
std::cout << tuple_index(i, t) << std::endl;
|
std::cout << tuple_index(t, i) << std::endl;
|
||||||
```
|
```
|
||||||
|
|
||||||
### 元组合并与遍历
|
### 元组合并与遍历
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ order: 10
|
|||||||
|
|
||||||
# 第 10 章 展望:C++20 简介
|
# 第 10 章 展望:C++20 简介
|
||||||
|
|
||||||
> 内容修订中, 目前内容为第一版中对 C++17 的展望
|
> 内容修订中
|
||||||
|
|
||||||
[TOC]
|
[TOC]
|
||||||
|
|
||||||
@@ -50,31 +50,6 @@ template <auto value> void foo() {
|
|||||||
foo<10>(); // value 被推导为 int 类型
|
foo<10>(); // value 被推导为 int 类型
|
||||||
```
|
```
|
||||||
|
|
||||||
### std::variant<>
|
|
||||||
|
|
||||||
熟悉 `boost` 的人应该很早就听说过 `variant<>` 了。`variant<>` 可以用于存储和操作不同类型的对象。我们在前面([对标准库的扩充:新增容器](./4.containers.md))对于迭代 `std::tuple` 时,简单使用了 `boost::variant<>`。提供给 `variant<>` 的类型模板参数可以让一个 `variant<>` 从而容纳提供的几种类型的变量(在其他语言(例如 Python/JavaScript 等)表现为动态类型)。
|
|
||||||
|
|
||||||
C++17 正式将 `variant<>` 纳入标准库,摇身一变成为 `std::variant<>`,有了它之后,我们可以将前面的代码更改为:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <variant>
|
|
||||||
template <size_t n, typename... Args>
|
|
||||||
std::variant<Args...> _tuple_index(size_t i, const std::tuple<Args...>& tpl) {
|
|
||||||
if (i == n)
|
|
||||||
return std::get<n>(tpl);
|
|
||||||
else if (n == sizeof...(Args) - 1)
|
|
||||||
throw std::out_of_range("越界.");
|
|
||||||
else
|
|
||||||
return _tuple_index<(n < sizeof...(Args)-1 ? n+1 : 0)>(i, tpl);
|
|
||||||
}
|
|
||||||
template <typename... Args>
|
|
||||||
std::variant<Args...> tuple_index(size_t i, const std::tuple<Args...>& tpl) {
|
|
||||||
return _tuple_index<0>(i, tpl);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 10.2 未入选特性
|
## 10.2 未入选特性
|
||||||
|
|
||||||
C++ 组委会在讨论投票最终确定 C++17 有很多提案,诸如 **Concepts**/**Ranges**/**Module** 等等,其中最受关注的就是 **Concepts**,可惜这一提案最终被拒,作为技术规范(Technical Specifications, TS) 将其发布。
|
C++ 组委会在讨论投票最终确定 C++17 有很多提案,诸如 **Concepts**/**Ranges**/**Module** 等等,其中最受关注的就是 **Concepts**,可惜这一提案最终被拒,作为技术规范(Technical Specifications, TS) 将其发布。
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <boost/variant.hpp>
|
#include <variant>
|
||||||
|
|
||||||
auto get_student(int id)
|
auto get_student(int id)
|
||||||
{
|
{
|
||||||
@@ -24,17 +24,16 @@ auto get_student(int id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <size_t n, typename... T>
|
template <size_t n, typename... T>
|
||||||
boost::variant<T...> _tuple_index(size_t i, const std::tuple<T...>& tpl) {
|
constexpr std::variant<T...> _tuple_index(const std::tuple<T...>& tpl, size_t i) {
|
||||||
if (i == n)
|
if constexpr (n >= sizeof...(T))
|
||||||
return std::get<n>(tpl);
|
|
||||||
else if (n == sizeof...(T) - 1)
|
|
||||||
throw std::out_of_range("越界.");
|
throw std::out_of_range("越界.");
|
||||||
else
|
if (i == n)
|
||||||
return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(i, tpl);
|
return std::variant<T...>{ std::in_place_index<n>, std::get<n>(tpl) };
|
||||||
|
return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(tpl, i);
|
||||||
}
|
}
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
boost::variant<T...> tuple_index(size_t i, const std::tuple<T...>& tpl) {
|
constexpr std::variant<T...> tuple_index(const std::tuple<T...>& tpl, size_t i) {
|
||||||
return _tuple_index<0>(i, tpl);
|
return _tuple_index<0>(tpl, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -42,6 +41,12 @@ auto tuple_len(T &tpl) {
|
|||||||
return std::tuple_size<T>::value;
|
return std::tuple_size<T>::value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T0, typename ... Ts>
|
||||||
|
std::ostream & operator<< (std::ostream & s, std::variant<T0, Ts...> const & v) {
|
||||||
|
std::visit([&](auto && x){ s << x;}, v);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
auto student = get_student(0);
|
auto student = get_student(0);
|
||||||
@@ -71,7 +76,7 @@ int main()
|
|||||||
auto new_tuple = std::tuple_cat(get_student(1), std::move(t));
|
auto new_tuple = std::tuple_cat(get_student(1), std::move(t));
|
||||||
|
|
||||||
// 迭代
|
// 迭代
|
||||||
for(int i = 0; i != tuple_len(new_tuple); ++i)
|
for(int i = 0; i != tuple_len(new_tuple); ++i) {
|
||||||
// 运行期索引
|
std::cout << tuple_index(new_tuple, i) << std::endl; // 运行期索引
|
||||||
std::cout << tuple_index(i, new_tuple) << std::endl;
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user