Skip to content

败犬日报 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)。