C++如何不使用字符串实现NumBase类按指定进制自定义初始化对象
可行性结论
- 第一种
NumBase<N> num = 字面量、第三种NumBase<N> num(字面量)写法可以实现 - 第二种
NumBase(8) num = 字面量写法不符合C++语法规则,完全无法实现,原因是模板参数必须在编译期确定,不能通过运行期传入的圆括号参数动态指定类型
核心前置限制
C++原生不支持无0x前缀的16进制字面量,也不支持12进制这类自定义进制的字面量解析,你示例中23F13A47、2312A47这类不带前缀/后缀的写法会被编译器识别为未定义标识符,无法直接编译,必须通过自定义用户定义字面量(UDL) 加后缀的方式,或者宏包裹的方式实现字面量解析。
具体实现代码(C++20及以上版本支持)
1. 编译期字面量解析工具与自定义字面量
#include <utility> // 编译期解析任意进制数字序列 template<char... Chars> constexpr unsigned long long parse_num(int base) { unsigned long long res = 0; auto cvt = [](char c) -> int { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'Z') return 10 + c - 'A'; if (c >= 'a' && c <= 'z') return 10 + c - 'a'; __builtin_unreachable(); }; ((res = res * base + cvt(Chars)), ...); return res; } // 各进制自定义字面量,后缀以下划线开头符合C++UDL规则 template<char... Chars> constexpr auto operator""_b8() { return parse_num<Chars...>(8); } template<char... Chars> constexpr auto operator""_b10() { return parse_num<Chars...>(10); } template<char... Chars> constexpr auto operator""_b16() { return parse_num<Chars...>(16); } template<char... Chars> constexpr auto operator""_b12() { return parse_num<Chars...>(12); }
2. NumBase模板类实现
template<int Base> class NumBase { unsigned long long val; public: // 接受解析后数值的构造函数,explicit可阻止隐式转换,按需开启 /* explicit */ constexpr NumBase(unsigned long long v) : val(v) {} // 示例成员函数:获取存储的数值 constexpr unsigned long long get() const { return val; } };
3. 使用示例
// 第一种初始化写法:拷贝初始化 NumBase<8> Num1 = 2312347_b8; NumBase<10> Num2 = 23123479_b10; NumBase<16> Num3 = 23F13A47_b16; NumBase<12> Num4 = 2312A47_b12; // 第三种初始化写法:直接初始化 NumBase<8> Num1_(2312347_b8); NumBase<10> Num2_(23123479_b10); NumBase<16> Num3_(23F13A47_b16); NumBase<12> Num4_(2312A47_b12);
所有初始化过程均无字符串入参,字面量解析全部在编译期完成,运行期无额外开销。
如果完全不能接受字面量加后缀,可改用宏实现,将字面量转为编译期字符串解析,用法为NumBase<16> Num3 = NUM(23F13A47,16),同样满足无字符串入参要求。
内容的提问来源于stack exchange,提问作者Alireza_mky
相关产品推荐
相关产品推荐

