如何在GNU C++23中为128位类型构建模板泛型约束?
针对__int128/unsigned __int128的C++23泛型约束实现
在GNU C23中,你可以利用**C20引入的concept特性**直接定义针对128位整数类型的泛型约束,替代函数/类体内的if constexpr判断,从模板重载决议阶段就限制类型范围。
1. 定义专属Concept
首先定义一个Int128 concept,明确限定类型只能是__int128或unsigned __int128:
#include <type_traits> // 方式1:直接用逻辑或组合类型判断 template <typename T> concept Int128 = std::same_as<T, __int128> || std::same_as<T, unsigned __int128>; // 方式2:用std::disjunction组合多个type trait(效果一致) // template <typename T> // concept Int128 = std::disjunction_v<std::same_as<T, __int128>, std::same_as<T, unsigned __int128>>;
2. 约束函数模板
用Int128约束函数模板,只有符合条件的类型才能实例化该函数:
#include <iostream> // 复用上面定义的Int128 concept // 仅接受__int128/unsigned __int128的打印函数 void print(Int128 auto value) { // 处理有符号128位整数的负号 if constexpr (std::same_as<decltype(value), __int128>) { if (value < 0) { std::cout << "-"; value = -value; } } // 递归转换为十进制输出(标准库不直接支持__int128的流输出) unsigned __int128 uval = static_cast<unsigned __int128>(value); if (uval >= 10) { print(uval / 10); } std::cout << static_cast<char>(uval % 10 + '0'); } // 测试代码 int main() { __int128 signed_val = -123456789012345678901234567890LL; unsigned __int128 unsigned_val = 987654321098765432109876543210ULL; print(signed_val); // 输出:-123456789012345678901234567890 std::cout << "\n"; print(unsigned_val); // 输出:987654321098765432109876543210 // int invalid_val = 10; // print(invalid_val); // 编译错误:int不满足Int128约束 return 0; }
3. 约束类模板
同样可以用Int128约束类模板的模板参数:
#include <iostream> #include <type_traits> template <typename T> concept Int128 = std::same_as<T, __int128> || std::same_as<T, unsigned __int128>; // 仅接受128位整数的包装类 template <Int128 T> class Int128Wrapper { private: T m_value; public: explicit Int128Wrapper(T val) : m_value(val) {} void print() const { if constexpr (std::same_as<T, __int128>) { if (m_value < 0) { std::cout << "-"; // 转换为无符号处理避免溢出 unsigned __int128 uval = static_cast<unsigned __int128>(-m_value); print_impl(uval); return; } } print_impl(static_cast<unsigned __int128>(m_value)); } private: static void print_impl(unsigned __int128 uval) { if (uval >= 10) { print_impl(uval / 10); } std::cout << static_cast<char>(uval % 10 + '0'); } }; // 测试代码 int main() { Int128Wrapper<__int128> wrapped_signed(-12345678901234567890LL); wrapped_signed.print(); // 输出:-12345678901234567890 std::cout << "\n"; Int128Wrapper<unsigned __int128> wrapped_unsigned(98765432109876543210ULL); wrapped_unsigned.print(); // 输出:98765432109876543210 // Int128Wrapper<int> invalid_wrap(10); // 编译错误:int不满足约束 return 0; }
关键区别说明
- 你之前用的
if constexpr是实例化后分支选择:模板会先为任意类型实例化,再通过编译期分支跳过不符合的代码,无法阻止无效类型的模板实例化。 - 用
concept是实例化前约束:编译器在重载决议阶段就会过滤掉不符合Int128的类型,直接拒绝无效实例化,真正实现泛型类型的范围限制。
注意:__int128是GNU编译器扩展,不属于C++标准类型,因此该代码仅能在支持此扩展的编译器(如GCC、Clang)下编译运行。
内容的提问来源于stack exchange,提问作者khteh
相关产品推荐
相关产品推荐

