如何实现C++字符串类自动识别编译时常量并启用constexpr构造优化?
需求与问题描述
我有一个编译期字符串类constexpr_str_t,能在编译时计算哈希、生成快速查表等,构造方式如下:
"hello"_constexpr_str;
我的string_t类支持从constexpr_str_t构造,实现了快速哈希、快速查找且避免不必要的数据拷贝,示例:
defs::string string = "hello"_constexpr_str;
同时string_t也支持通过const char_T*构造。
当前需求:当使用string("hell word!")这类编译时常量构造string_t时,无需手动添加_constexpr_str后缀,自动在编译时将其转换为string("hell word!"_constexpr_str)的逻辑——也就是自动计算常量字符串的相关信息并存入常量存储,让string_t仅持有指向constexpr_str_t的指针。
我写了一段草稿代码:
//Draft Code #if defined(__cpp_if_consteval) #define if_in_consteval if consteval #else #define if_in_consteval if constexpr(0) #endif constexpr string_t(const constexpr_str_t& str) noexcept; // 保存指向constexpr_str_t的指针 string_t(const char_T* str) noexcept{ if_in_consteval{ constexpr constexpr_str_t constexpr_str(str); construct[this](constexpr_str); } else{ construct[this](string_view_t(str)); } }
请问该如何正确实现这一需求?
实现方案
1. 基于C++20的最优实现:模板化consteval构造函数
核心是通过数组引用模板参数精准匹配字符串字面量,用consteval限定仅在编译期触发,自动复用constexpr_str_t的编译期能力:
#include <type_traits> // 保留原有constexpr_str_t构造函数,直接复用编译期计算结果 constexpr string_t(const constexpr_str_t& str) noexcept { this->constexpr_ptr = &str; this->precomputed_hash = str.hash(); // 其他编译期预计算字段的赋值 } // 运行期专属的const char_T*构造函数,处理非常量输入 string_t(const char_T* str) noexcept : string_t(string_view_t(str)) {} // 编译期专属构造函数,仅匹配字符串字面量(编译期常量) template <size_t N> consteval string_t(const char_T (&str)[N]) noexcept : string_t(constexpr_str_t(str)) {}
- 模板参数
const char_T (&str)[N]会自动匹配字符串字面量,普通const char_T*指针(运行期传入)不会触发这个构造函数 consteval确保该构造函数只能在编译期执行,强制生成constexpr_str_t实例并复用其编译期计算结果
2. 兼容C++20的分支实现(用std::is_constant_evaluated)
如果需要兼容C++20但不想拆分构造函数,可以用std::is_constant_evaluated()区分编译期/运行期分支:
#include <type_traits> string_t(const char_T* str) noexcept { if (std::is_constant_evaluated()) { // 编译期分支:构造constexpr_str_t并复用 constexpr constexpr_str_t constexpr_str(str); *this = string_t(constexpr_str); } else { // 运行期分支:按普通字符串处理 *this = string_t(string_view_t(str)); } }
注意:std::is_constant_evaluated()能准确识别当前是否处于编译期求值上下文,避免将运行期指针误判为编译期常量。
3. 优化:避免重复生成constexpr_str_t实例
为了避免相同字符串字面量多次构造constexpr_str_t,可以用静态模板存储全局常量实例:
// 全局模板 holder,存储编译期生成的constexpr_str_t实例 template <const char_T* Str> struct ConstexprStrStorage { static constexpr constexpr_str_t value{Str}; }; // 编译期构造函数,复用全局存储的实例 template <const char_T* Str> consteval string_t() noexcept : string_t(ConstexprStrStorage<Str>::value) {} // 配合宏简化调用(可选,也可直接用字面量匹配的模板构造) #define CONST_STRING(str) string_t<STR_LITERAL(str)>()
关键注意事项
- 确保
constexpr_str_t的构造函数是constexpr/consteval的,所有哈希、查表计算逻辑必须能在编译期完成 - 数组引用模板参数是区分字符串字面量和普通指针的核心,不要直接用
const char_T*作为模板参数 - 若需兼容C++17及更早版本,可借助编译器扩展(如GCC的
__builtin_constant_p)替代std::is_constant_evaluated()
内容的提问来源于stack exchange,提问作者steve02081504
相关产品推荐
相关产品推荐

