如何在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)。
原代码问题分析
你提供的代码无法正常工作,核心问题有两点:
- 模板特化参数不匹配:主模板的第二个模板参数默认是
void,但特化版本中std::enable_if_t的第二个参数指定为std::uint8_t/std::uint16_t,导致特化的模板参数列表与主模板不兼容,永远只会匹配主模板的type = void。 - 特化条件无优先级:即使参数匹配,若不对更大类型的特化条件添加“排除更小类型范围”的限制,会出现多个特化同时匹配的歧义问题。
正确实现方案
方案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
相关产品推荐
相关产品推荐

