C++17的入选特性有
非类型模板参数的 auto
模板参数分为两种,一种是类型模板参数,也是我们用得最多的一种:
template <typename T, typename U>
auto add(T t, U u) {return t+u;
}
里面的 T 和 U 都是类型模板参数。另一种是非类型模板参数,它可以让不同的字面量成为模板的参数:
template <typename T, int BufSize>
class buffer_t {
public:T& alloc();void free(T& item);
private:T data[BufSize];
}buffer_t<int, 100> buf; // 100 作为模板参数
遗憾的是我们在编写模板的时候就必须明确非类型模板参数的具体类型,C++17 打破了这一限制,让我们能够在非类型模板参数中使用 auto 关键字,从而让编译器推导具体的类型:
template <auto value> void foo() {return;
}foo<10>(); // value 被推导为 int 类型
std::variant<>
熟悉 boost 的人应该很早就听说过 variant<> 了。variant<> 可以用于存储和操作不同类型的对象。我们在前面(对标准库的扩充:新增容器)对于迭代 std::tuple 时,简单使用了 boost::variant<>。提供给 variant<> 的类型模板参数可以让一个 variant<> 从而容纳提供的几种类型的变量(在其他语言(例如 Python/JavaScript 等)表现为动态类型)。
C++17 正式将 variant<> 纳入标准库,摇身一变成为 std::variant<>,有了它之后,我们可以将前面的代码更改为:
#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("越界.");elsereturn _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);
}
结构化绑定(Structured bindings)
结构化绑定提供了类似其他语言中提供的多返回值的功能。到目前为止,我们可以通过 std::tuple 来构造一个元组,囊括多个返回值。但缺陷是显而易见的,我们没有一种简单的方法直接从元组中拿到并定义元组中的元素,尽管我们可以使用 std::tie 对元组进行拆包,但我们依然必须非常清楚这个元组包含多少个对象,各个对象是什么类型。
C++17 给出的结构化绑定可以让我们写出这样的代码:
std::tuple<int,double,std::string> f() {return std::make_tuple(1,2.3,"456");
}
auto [x,y,z] = f(); // x,y,z 分别被推导为int,double,std::string
变量声明的强化
变量的声明在虽然能够位于任何位置,甚至于 for 语句内能够声明一个临时变量 int,但始终没有办法在 if 和 switch语句中声明一个临时的变量。例如:
auto p = map_container.try_emplace(key, value);
if(!p.second) {//...
} else {//...
}
C++17 消除了这一限制,使得我们可以:
if (auto p = m.try_emplace(key, value); !p.second) { //...
} else {//...
}