编译时移除string_view中子串的方法及DBG宏优化问询
解决嵌套DBG宏的编译时字符串清理问题
要实现你期望的嵌套DBG宏输出效果,核心是在编译时处理#expression生成的原始字符串,移除所有宏调用形式的DBG(前缀,同时保留表达式的结构。下面是完整的实现方案,基于C++17/20的constexpr特性:
完整代码实现
#include <iostream> #include <string_view> // 编译时计算清理后的字符串长度 constexpr size_t calculate_cleaned_length(std::string_view s) { constexpr std::string_view target = "DBG("; size_t len = s.size(); size_t pos = 0; while ((pos = s.find(target, pos)) != std::string_view::npos) { // 替换"DBG("为"(", 每替换一次减少3个字符(4-1=3) len -= target.size() - 1; pos += target.size(); } return len; } // 编译时将原始字符串填充到目标数组,替换所有"DBG("为"(" template<size_t N> constexpr void fill_cleaned_string(char (&dest)[N], std::string_view s) { constexpr std::string_view target = "DBG("; size_t dest_idx = 0; size_t pos = 0; while (pos < s.size()) { // 检查当前位置是否匹配"DBG(" if (pos + target.size() <= s.size() && s.substr(pos, target.size()) == target) { dest[dest_idx++] = '('; pos += target.size(); } else { dest[dest_idx++] = s[pos++]; } } dest[dest_idx] = '\0'; // 确保字符串以终止符结尾 } // 调试日志函数,与你原版本一致 template<typename T> inline constexpr T debug_log(const std::string_view& raw_expression, T&& x) { std::cout << raw_expression << " = " << x << '\n'; return std::forward<T>(x); } // 改进后的DBG宏,内置编译时字符串清理逻辑 #define DBG(expression) \ []() constexpr { \ constexpr std::string_view raw_expr = #expression; \ constexpr size_t cleaned_size = calculate_cleaned_length(raw_expr); \ constexpr char cleaned_buf[cleaned_size + 1]{}; \ fill_cleaned_string(cleaned_buf, raw_expr); \ return debug_log(std::string_view(cleaned_buf), expression); \ }() // 测试代码 int main() { DBG(DBG(5*3)+DBG(20/4)); // 输出结果: // 5*3 = 15 // 20/4 = 5 // (5*3)+(20/4) = 20 return 0; }
关键实现细节
编译时字符串长度计算:
calculate_cleaned_length会遍历原始字符串,统计所有DBG(出现的次数,计算出清理后的字符串总长度。这一步完全在编译时完成,不会带来运行时开销。编译时字符串替换:
fill_cleaned_string将原始字符串中的每一处DBG(替换为(,并填充到一个编译时分配的字符数组中。使用模板数组参数确保大小匹配,避免越界。改进的DBG宏:
利用constexpr lambda在编译时完成字符串清理工作:- 首先通过
#expression获取原始表达式字符串; - 计算清理后的长度并创建对应大小的constexpr字符数组;
- 填充清理后的字符串;
- 调用
debug_log传入清理后的字符串和求值后的表达式结果。
- 首先通过
嵌套调用的执行顺序:
内层的DBG调用会先执行,输出各自的表达式和结果;外层DBG会在所有内层调用完成后,输出清理后的合并表达式和最终结果,完全符合你的期望。
兼容性说明
- 代码基于C++17标准,需要编译器支持constexpr lambda和constexpr std::string_view操作(GCC 7+、Clang 5+、MSVC 2017+都支持)。
- 如果使用C++20,可以将
fill_cleaned_string中的子串检查替换为starts_with,代码会更简洁:if (s.substr(pos).starts_with(target)) {
内容的提问来源于stack exchange,提问作者Jack Sabbath
相关产品推荐
相关产品推荐

