如何在C++20中基于通用字符类型创建字符串字面量?
在C++20中基于通用字符类型创建字符串字面量
我们可以借助C++20的非类型模板参数扩展特性,实现一个通用的字符串字面量转换工具gstring,支持将任意字符类型的字面量转换为目标字符类型的编译期字符串。
核心实现代码
#include <iostream> #include <cstring> #include <algorithm> #include <string> namespace detail { // 编译期单个字符类型转换 template<typename DestChar, typename SrcChar> constexpr DestChar char_cast(SrcChar c) noexcept { return static_cast<DestChar>(c); } // 编译期字符串转换模板,生成目标字符数组 template<typename DestChar, std::size_t N, typename SrcChar> struct converted_string { constexpr converted_string(const SrcChar (&src)[N]) noexcept { for (std::size_t i = 0; i < N; ++i) { data[i] = char_cast<DestChar>(src[i]); } } DestChar data[N]; }; // 自动推导源字符串的长度与类型 template<typename DestChar, typename SrcChar, std::size_t N> converted_string(const SrcChar (&)[N]) -> converted_string<DestChar, N, SrcChar>; } // 字符串字面量包装器,用于捕获字面量内容作为非类型模板参数 template<std::size_t N> struct StringLiteral { constexpr StringLiteral(const char (&str)[N]) noexcept { std::copy_n(str, N, value); } char value[N]; }; template<std::size_t N> struct WideStringLiteral { constexpr WideStringLiteral(const wchar_t (&str)[N]) noexcept { std::copy_n(str, N, value); } wchar_t value[N]; }; // 推导指南,简化包装器的使用 template<std::size_t N> StringLiteral(const char (&)[N]) -> StringLiteral<N>; template<std::size_t N> WideStringLiteral(const wchar_t (&)[N]) -> WideStringLiteral<N>; // 对外接口:将包装后的字面量转换为目标字符类型的字符串指针 template<typename StringLiteral, typename DestChar> constexpr const DestChar* gstring() noexcept { static constexpr detail::converted_string<DestChar> conv{StringLiteral{}.value}; return conv.data; }
测试用例验证
int main(int argc, char const* argv[]) { { constexpr wchar_t const* v = gstring<StringLiteral<12>("hello world"), wchar_t>(); std::wcout << v << std::endl; std::wcout << std::wcslen(v) << std::endl; } { constexpr char const* v = gstring<WideStringLiteral<12>(L"world hello"), char>(); std::cout << v << std::endl; std::cout << std::strlen(v) << std::endl; } return 0; }
输出结果
hello world 11 world hello 11
实用场景示例
在模板函数中,无需为不同字符类型编写重复的字符串字面量:
template <typename TChar> void AddFoo(std::basic_string<TChar> & s){ s.append( gstring<StringLiteral<4>("foo"), TChar>() ); }
实现关键点
- 非类型模板参数捕获字面量:通过
StringLiteral和WideStringLiteral包装结构体,将字符串字面量的内容作为非类型模板参数传递,符合C++20的语法规则 - 编译期转换:所有转换逻辑都在编译期完成,运行时无额外开销
- 通用适配:支持任意源字符类型到目标字符类型的转换,可扩展
char_cast函数处理复杂字符集(如UTF-8/16转换)
内容的提问来源于stack exchange,提问作者bradgonesurfing
相关产品推荐
相关产品推荐

