【C++】编译期if
1. 背景
template<typename T>
void foo(T t) {
if (std::is_same_v<T,int>)
{
std::cout << "int\n";
}
else if(std::is_same_v<T,double>)
{
std::cout <<"double\n";
}
}
上面这段代码无法通过编译。
2. if constexpr
使用编译期if,模板实例化时,false分支将被丢弃不参与模板实例化,但注意仍然会检查语法正确性,若语法不对也还是会编译不过。
template<typename T>
void foo(T t) {
if constexpr(std::is_same_v<T,int>)
{
std::cout << "int\n";
}
else if constexpr(std::is_same_v<T,double>)
{
std::cout <<"double\n";
}
}
3. 应用场景
针对模板参数的类型/数值等,在编译期决定“这段源码要不要参与编译”,从而避免运行期分支、避免实例化无效代码。
- 按类型裁剪代码(最常见)
if constexpr (std::is_pointer_v<T>)
*t = 0;
else
std::sort(t.begin(), t.end());
- 按数值裁剪代码
template<int N>
auto fact() {
if constexpr (N <= 1) return 1;
else return N * fact<N-1>();
}
* 按编译期布尔常量裁剪
constexpr bool use_fast_path = sizeof(void*) == 8;
if constexpr (use_fast_path) { /* AVX2 版本 */ }
else { /* 标量版本 */ }
- 避免实例化无效成员函数
template<typename T>
struct S {
void serialize() const {
if constexpr (Serializable<T>) { /* … */ }
else static_assert(always_false<T>, "T must be serializable");
}
};
- 替代 #ifdef 的“类型安全版本”
不需要预处理器,可直接利用 if constexpr (PLATFORM_WINDOWS) 等常量表达式。
4. 与预处理if endif对比
#if 0
#endif
预处理属于纯文本处理,不检查语法,内部代码即使有语法错误也不会影响编译。
if constexpr是不参与模板实例化,但会检查语法。