CTTCG 08 Compile-Time Programming
模板元编程
略。
constexpr
函数
在 C++11 中只能使用一条语句,而在 C++14 之后可以使用的语句变得丰富。constexpr
函数允许编译期优化,但不阻止运行期使用。作为对比,C++20 consteval
只能在编译期使用。
应用:e.g. 常量表达式函数可以计算出一些基本信息,比如判断一个整数是否为素数,以此做为另一个模板类偏特化的依据。
SFINAE
substitution failure is not an error
有一些地方需要注意:寻找函数 candidates 时只会考虑函数模板的函数签名,不会考虑函数体。用 C++14 auto 省略掉返回值类型之后,也不会考虑返回值类型。如果匹配完成之后函数体不能编译,编译器就会报错。
Case 1:在返回值中携带约束信息
如果注释掉行 [1],代码将无法编译,这是因为第一个版本被选择了,但是它的函数体编译失败了。留下含 decltype 的箭头返回值声明可以对参数 t 提出更具体的要求。
Case 2:在返回值中携带约束的一般写法
上面的代码要求了 T 中有一个类型别名为 size_type
。还要求有一个函数 T::size()
。注意第一个参数前面被转换成了 void,否则可能因为用户重载了逗号运算符而出现意外的错误。
虽然现在 C++20 已经能够用约束处理此类问题,但是要求”**某类型具有某成员“**的约束需要 requires 体(而不是 requires 条件),也就是必须在 concept 中定义。这样会出现很多意义不是很明显的小 concept(同样也是命名危机)。
用 requires 可以做到类似的存在性检测:
template <typename T>
auto len(T const& t)
requires(decltype((void)std::declval<typename T::size_type>(),
// (void)t.size(), true){true})
(void)t.size(), 0){}, true)
// 这两种写法都可以,前面是存在性检测,
// 后面的true是其他条件,可以更换成concept组成的表达式
{
return t.size();
}
if constexpr (…)
略。