C++17 详解 14
本文为 《C++17 in detail》 一书的中文渣中渣译文,不足之处还望指正。
4.4 用 auto
声明非类型模版参数
这是在任何地方使用 auto 策略的另一部分。C++11/14 里你可以利用 auto 自动推断变量甚至返回值的类型,另外还有泛型 lambda。现在你也可以利用它推断非类型模版参数了。
比如:
1 | template <auto value> void f() { } |
这很实用,因为你不必为指明非类型参数的类型而添加一个独立的参数了。
比如 C++11/14 里:
1 | template <typename Type, Type value> constexpr Type TConstant = value; |
C++17 里代码能稍稍简洁一点:
1 | template <auto value> constexpr auto TConstant = value; |
不需要再显式地写明 Type 了。
异构编译时链表作为一种进阶用法在大量论文、文章中被引用:
1 | template <auto ... vs> struct HeterogenousValueList {}; |
C++17 之前是不可能直接声明这样一个链表的,首先必须提供某种封装类。
4.5 其它修改
C++17 里还有其它一些跟模版相关的语言特性值得一提:
允许在模版的模版参数中使用 typename
译注:模版的模版参数(template template parameters),参数为模版的模版。
声明模版的模版参数时允许使用 typename 代替 class 关键字。普通类型参数可以互换使用两者,但是之前模版的模版参数被限制为只能使用 class。
更多信息参考 N4051。
允许对所有非类型模版实参进行常量估算
移除对指针、引用、成员指针作为非类型模版参数时的语法限制。
更多信息参考 N4268。
萃取中的变量模版
所有产出 ::value 的类型萃取都有一个伴随的 _v 变量模版。比如:
std::is_integral<T>::value
可以变成 std::is_integral_v<T>
std::is_class<T>::value
可以变成 std::is_class_v<T>
此改进源自 C++14 对返回 ::type 类型萃取添加的 _t 后缀(类型别名)。
更多信息参考 P0006R0。
using 声明中的包展开
此特性是对可变参模版和参数包的加强。
现在编译器支持在包扩展中使用 using 关键字:
1 | template<class... Ts> struct overloaded : Ts... { |
overloaded 类暴露所有来自基类的 operator() 重载版本。C++17 之前你必须递归使用参数包以实现相同结果。 overloaded 模式是对 std::visit 一个很有用的加强,在(后边)Variant 一章的 Overload 小节有更多讨论。
更多信息参考 P0195。
逻辑操作元函数
C++17 添加了一些趁手的模版元函数:
template<class... B> struct conjunction;
- 逻辑与template<class... B> struct disjunction;
- 逻辑或template<class B> struct negation;
- 逻辑非
这里是一份基于提案代码的示例:
1 | template<typename... Ts> |
PrintIntegers 函数同一组可变数量的参数一起工作,但是参数必须都是 int 类型。
这些辅助类元函数能提高复杂模版代码的可读性。
更多信息参考 P0013。
4.6 编译器支持
略。