败犬日报 2025-01-15
1. 非模板语境下,if constexpr
对未命中分支做语义检查
这样写会编译报错:
cpp
int main() {
uint32_t x;
if constexpr (std::is_integral_v<decltype(x)>) {
std::cout << 111 << std::endl;
} else {
static_assert(false);
}
return 0;
}
一个不那么优雅的方案是拷贝一下 if constexpr
里的条件,这样 static_assert
求值出来是 true,可以编译通过:
cpp
int main() {
uint32_t x;
if constexpr (std::is_integral_v<decltype(x)>) {
std::cout << 111 << std::endl;
} else {
static_assert(std::is_integral_v<decltype(x)>);
}
return 0;
}
另一个是把 if constexpr
放进模板里:
cpp
template <typename T>
void f(T x) {
if constexpr (std::is_integral_v<decltype(x)>) {
std::cout << 111 << std::endl;
} else {
static_assert(false);
}
}
int main() {
uint32_t x;
f(x);
return 0;
}
早期对分支的语义检查时机是在模板实例化前,CWG2518 把这个时机往后挪了,所以较新版本的编译器可以直接 static_assert(false)
。
但如果是较旧的编译器(GCC 12 及以下),可以在 if constexpr
放进模板的基础上,使用惰性求值的方法,https://zh.cppreference.com/w/cpp/language/if 有记载:
cpp
template<typename>
constexpr bool dependent_false_v = false;
template<typename T>
void f()
{
if constexpr (std::is_arithmetic_v<T>)
// ...
else {
// CWG2518 前的变通方案
static_assert(dependent_false_v<T>, "必须是算术类型"); // OK
}
}
2. 模板函数和函数模板
是一个东西。函数模板 (Function Template) 更专业一点,毕竟这个东西不是函数。
同理还有类模板 (Class Template)。