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 (…)

略。