如何为带约束非类型参数的阶乘类模板实现全整数类型0值特化
解决方案:为所有整数类型的0实现阶乘特化
原代码的问题在于factorial<0>的全特化仅匹配int类型的0,导致其他整数类型(如unsigned int、long等)的0值无法触发终止递归的特化,进而引发无限模板实例化。以下是两种无需逐个编写特化的解决方法:
方法1:C++20+ 利用偏特化匹配所有整数类型的0
借助C++20的std::integral概念,直接针对任意整数类型的0值编写偏特化:
#include <concepts> template <std::integral auto num> struct factorial { constexpr static auto val{num * factorial<num - 1>::val}; }; // 偏特化:匹配所有值为0的std::integral类型非类型参数 template <std::integral T> struct factorial<T{0}> { constexpr static auto val{1}; }; // 验证 static_assert(factorial<4>::val == 24); // int类型正常 static_assert(factorial<4u>::val == 24); // unsigned int类型正常 static_assert(factorial<0l>::val == 1); // long类型正常 static_assert(factorial<0ull>::val == 1); // unsigned long long类型正常
这里的factorial<T{0}>会自动匹配所有整数类型的0值,不管是有符号/无符号、不同长度的整数,都能触发终止递归的特化。
方法2:兼容更早C++版本的实现
如果环境不支持C++20概念,可以用std::is_integral结合enable_if实现相同效果:
#include <type_traits> template <auto num, typename = void> struct factorial { constexpr static auto val{num * factorial<num - 1>::val}; }; // 偏特化:筛选值为0的整数类型参数 template <auto num> struct factorial<num, std::enable_if_t<std::is_integral_v<decltype(num)> && (num == 0)>> { constexpr static auto val{1}; }; // 验证 static_assert(factorial<4>::val == 24); static_assert(factorial<4u>::val == 24); static_assert(factorial<0l>::val == 1);
额外推荐:更简洁的constexpr函数实现
C++14及以上可以直接用constexpr函数实现编译期阶乘,无需模板特化,天然支持所有整数类型:
#include <concepts> constexpr std::integral auto factorial(std::integral auto num) { return num == 0 ? 1 : num * factorial(num - 1); } // 验证 static_assert(factorial(4) == 24); static_assert(factorial(4u) == 24); static_assert(factorial(0l) == 1);
内容的提问来源于stack exchange,提问作者paolo
相关产品推荐
相关产品推荐

