C++17如何用constexpr替换字符串字面量拼接的预处理器宏
C++17 替换字符串字面量拼接宏的实现方案
原宏依赖预处理器对相邻字符串字面量的自动拼接能力,C++17可以通过constexpr构造编译期字符串结构实现完全等价的零开销替换,不需要保留任何预处理器宏。
实现步骤
- 首先实现一个轻量的编译期固定长度字符串工具,支持constexpr语境下的拼接操作:
#include <array> #include <utility> #include <string_view> template<std::size_t N> struct ConstStr { std::array<char, N> buffer{}; // 支持从字符串字面量隐式构造 constexpr ConstStr(const char (&str)[N]) { for (std::size_t i = 0; i < N; ++i) { buffer[i] = str[i]; } } // 拼接场景的内部构造函数 constexpr ConstStr(std::string_view sv, std::integral_constant<std::size_t, N>) { for (std::size_t i = 0; i < sv.size(); ++i) { buffer[i] = sv[i]; } buffer[N - 1] = '\0'; } // 兼容C风格字符串和string_view使用场景 constexpr const char* c_str() const noexcept { return buffer.data(); } constexpr operator std::string_view() const noexcept { return {buffer.data(), N - 1}; } }; // constexpr拼接运算符重载 template<std::size_t N1, std::size_t N2> constexpr auto operator+(const ConstStr<N1>& a, const ConstStr<N2>& b) { std::array<char, N1 + N2 - 1> tmp{}; std::size_t pos = 0; for (std::size_t i = 0; i < N1 - 1; ++i) tmp[pos++] = a.buffer[i]; for (std::size_t i = 0; i < N2 - 1; ++i) tmp[pos++] = b.buffer[i]; tmp[pos] = '\0'; return ConstStr<N1 + N2 - 1>(tmp.data(), std::integral_constant<std::size_t, N1 + N2 - 1>{}); }
- 直接替换原有宏定义和数组声明,所有逻辑均在编译期执行:
// 替换原#define FNAME "first" constexpr ConstStr FNAME = "first"; // 替换原#define LNAME "last" constexpr ConstStr LNAME = "last"; // 替换原#define NAME FNAME LNAME constexpr auto NAME = FNAME + LNAME; // 替换原const char hello[] = "hello " NAME; constexpr auto hello = ConstStr("hello ") + NAME;
效果说明
- 所有拼接计算完全在编译阶段完成,和原宏实现相比没有任何运行时开销,生成的二进制内容完全一致
hello.c_str()可以直接获取到const char*类型的C风格字符串,和原代码中hello数组的使用方式完全兼容- 全程使用C++17标准特性:
constexpr、类模板、std::array、std::string_view、运算符重载,没有任何宏定义参与 - 如果仅需要临时读取字符串内容、不需要持有字符数组,可以直接用
std::string_view做编译期拼接,不需要自定义ConstStr结构,但该方式无法直接生成全局可用的C风格字符数组。
内容的提问来源于stack exchange,提问作者Baruch
相关产品推荐
相关产品推荐

