You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:57:36