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

如何在C++20中实现编译期推导适配值的最小无符号整数类型

实现smallest_unsigned_fitting_t类型别名的正确方案

需求说明

要实现一个编译期类型别名smallest_unsigned_fitting_t<n>,根据给定的编译期无符号整数n,推导出能容纳该值的最小标准无符号整数类型:

  • 当n = 42时,推导为std::uint8_t
  • 当n = 513时,推导为std::uint16_t
  • 以此类推,支持std::uint8_t/std::uint16_t/std::uint32_t/std::uint64_t的自动匹配,允许使用C++20特性(如std::in_range)。

原代码问题分析

你提供的代码无法正常工作,核心问题有两点:

  1. 模板特化参数不匹配:主模板的第二个模板参数默认是void,但特化版本中std::enable_if_t的第二个参数指定为std::uint8_t/std::uint16_t,导致特化的模板参数列表与主模板不兼容,永远只会匹配主模板的type = void。
  2. 特化条件无优先级:即使参数匹配,若不对更大类型的特化条件添加“排除更小类型范围”的限制,会出现多个特化同时匹配的歧义问题。

正确实现方案

方案1:嵌套std::conditional_t(简洁直观)

利用C++20的std::in_range结合std::conditional_t按从小到大的顺序判断,第一个满足条件的类型即为最小适配类型:

#include <cstdint>
#include <type_traits>

template<std::size_t n>
struct smallest_unsigned_fitting {
    using type = std::conditional_t<
        std::in_range<std::uint8_t>(n),
        std::uint8_t,
        std::conditional_t<
            std::in_range<std::uint16_t>(n),
            std::uint16_t,
            std::conditional_t<
                std::in_range<std::uint32_t>(n),
                std::uint32_t,
                std::uint64_t
            >
        >
    >;
};

template<std::size_t n>
using smallest_unsigned_fitting_t = typename smallest_unsigned_fitting<n>::type;

// 测试验证
static_assert(std::is_same_v<smallest_unsigned_fitting_t<42>, std::uint8_t>);
static_assert(std::is_same_v<smallest_unsigned_fitting_t<513>, std::uint16_t>);
static_assert(std::is_same_v<smallest_unsigned_fitting_t<65537>, std::uint32_t>);
static_assert(std::is_same_v<smallest_unsigned_fitting_t<4294967297ULL>, std::uint64_t>);

方案2:模板特化+requires约束(更灵活)

通过C++20的requires约束为每个特化添加精确匹配条件,确保最小类型优先匹配:

#include <cstdint>
#include <type_traits>

// 主模板
template<std::size_t n>
struct smallest_unsigned_fitting;

// 匹配uint8_t范围(0~255)
template<std::size_t n>
requires std::in_range<std::uint8_t>(n)
struct smallest_unsigned_fitting<n> {
    using type = std::uint8_t;
};

// 匹配uint16_t范围(256~65535),排除uint8_t的情况
template<std::size_t n>
requires (!std::in_range<std::uint8_t>(n) && std::in_range<std::uint16_t>(n))
struct smallest_unsigned_fitting<n> {
    using type = std::uint16_t;
};

// 匹配uint32_t范围(65536~4294967295),排除更小类型的情况
template<std::size_t n>
requires (!std::in_range<std::uint16_t>(n) && std::in_range<std::uint32_t>(n))
struct smallest_unsigned_fitting<n> {
    using type = std::uint32_t;
};

// 匹配uint64_t范围(4294967296~18446744073709551615)
template<std::size_t n>
requires (!std::in_range<std::uint32_t>(n))
struct smallest_unsigned_fitting<n> {
    using type = std::uint64_t;
};

template<std::size_t n>
using smallest_unsigned_fitting_t = typename smallest_unsigned_fitting<n>::type;

// 测试验证
static_assert(std::is_same_v<smallest_unsigned_fitting_t<42>, std::uint8_t>);
static_assert(std::is_same_v<smallest_unsigned_fitting_t<513>, std::uint16_t>);
static_assert(std::is_same_v<smallest_unsigned_fitting_t<65537>, std::uint32_t>);
static_assert(std::is_same_v<smallest_unsigned_fitting_t<4294967297ULL>, std::uint64_t>);

使用示例

#include <array>

constexpr std::size_t a = 42;
constexpr std::array<smallest_unsigned_fitting_t<a>, 1234> arr{}; // arr的元素类型为std::uint8_t

constexpr std::size_t b = 513;
constexpr std::array<smallest_unsigned_fitting_t<b>, 1234> arr2{}; // arr2的元素类型为std::uint16_t

内容的提问来源于stack exchange,提问作者Adomas Baliuka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:21:06