如何在编译时从string_view中删除子字符串?
How to remove a substring from a string_view at compile time?
我创建了一个名为DBG的宏,它打印表达式本身及其计算值。所以DBG(5+1)
应该打印5+1 = 6
.该宏工作正常。
然而,如果我封装了多个宏,那将变得非常不可读,因为"DBG"本身总是被拖来拖去。
我想做的是在编译时从表达式本身中删除子字符串"DBG"的所有出现。这样DBG(DBG(5*3) + DBG(20/4))
结果就不会
5*3 = 15
20/4 = 5
DBG(5*3)+DBG(20/4) = 20
而是相反
5*3 = 15
20/4 = 5
(5*3)+(20/4) = 20
如果需要:宏如下所示:#define DBG(expression) debug_log((#expression, expression)
debug_log是:
template<typename T>
inline constexpr T debug_log(const std::string_view& raw_expression, T&& x)
{
using namespace std;
cout << raw_expression << " = " << x << endl;
return x;
}
我已经编写了一个应该这样做的辅助函数,但我无法弄清楚如何在编译时连接两个string_views。
inline constexpr auto clean_expression(const std::string_view& expression)
{
constexpr std::string_view macro_name = "DBG";
constexpr auto marco_name_length = macro_name.size();
auto pos = expression.find(macro_name);
if (pos == -1) {
return expression;
}
else {
auto after_macro_name = expression.substr(pos + marco_name_length);
auto length_before_macro = expression.size() - after_macro_name.size() - marco_name_length;
std::string_view string_before_macro_name = expression.substr(0, length_before_macro);
// TODO: Finish implementation by concatenating the string_before_macro_name and after_macro_name and cleaning the result
//auto partly_cleaned_string = concatenate(string_before_macro_name, after_macro_name)}; <-- that one is missing
//return clean_expression(partly_cleaned_string);
}
}
您当前的策略不起作用,因为std::string_view
必须指向一些现有的连续数据块。因此,除非您返回string_view
的单个切片,否则您必须分配一个 char 数组并将其返回到结构中:
template <size_t N>
struct fixed_string {
char data[N];
};
现在,除非你想做 C 风格的事情并选择最大长度的缓冲区,否则你需要将表达式大小作为编译时常量(知道这是一个上限(。这。。。不起作用,因为函数参数不是 constexpr:
constexpr auto clean_expression(std::string_view& expression) {
fixed_string<expression.size()> result; // fails
/*...*/
return result;
}
因此,听起来很奇怪,为了安全起见,您需要将输入作为普通的旧字符数组传递:
template <size_t N>
constexpr auto clean_expression(const char (&expr)[N]) {
fixed_string<N> result = {};
/* ... */
return result;
}
由于我们知道结果大小将小于或等于缓冲区大小,因此我们可以添加一个字段以使其可用作字符串:
template <size_t N>
struct fixed_string {
constexpr std::string_view view() const { return { data, size }; }
char data[N];
size_t size;
};
之后,只需跳过std::string
方法并编写一个小循环来有选择地复制字符:
template <size_t N>
template <size_t N>
constexpr auto clean_expression(const char (&expr)[N]) {
fixed_string<N> result = {};
int src_idx = 0;
int dst_idx = 0;
while (src_idx < N - 2) {
if (expr[src_idx] == 'D' && expr[src_idx+1] == 'B' && expr[src_idx+2] == 'G') {
src_idx += 3;
} else {
result.data[dst_idx++] = expr[src_idx++];
}
}
result.data[dst_idx++] = expr[N-2];
result.data[dst_idx++] = expr[N-1];
result.size = dst_idx;
return result;
}
并使用:
constexpr auto expr = clean_expression("DBG(DBG(y) + DBG(z))");
std::cout << expr.view(); // ((y) + (z))
演示:https://godbolt.org/z/8j3RCs
需要注意的是,在使用之前必须将其设置为变量,因为此表达式的结果仍然是临时的,而不是全局的。如果将其直接传递给函数参数,则视图的寿命将超过对象。
也许这可能不适合您,因为您希望将宏直接粘贴到字符串文本的位置。但你可能会侥幸逃脱,因为清理的字符串数据可能位于全局数据部分中,并且生成的未定义行为将具有预期的输出。
- 将数组的地址分配给变量并删除
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- C/C++编译器通常会删除重复的库吗
- 从链接列表c++中删除一个项目
- C++如何通过用户输入删除列表元素
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 是否需要删除包含对象的"pair"?
- 如何在自删除后将对象设置为nullptr
- 迭代时从向量和内存中删除对象
- 使用函数"remove"删除重复元素
- 如何从多映射中删除特定的重复项
- 运算符C++ "delete []"仅删除 2 个前值
- 删除指向指针的指针是运行时错误吗
- 将指针设置为"nullptr"并不能防止双重删除?
- 为什么示例代码访问IUnknown中已删除的内存
- 如何通过 getter 函数删除矢量的元素?
- 从控制台中删除最后打印的元素
- C++中的线程安全删除
- 如何从存储在std::映射中的std::集中删除元素
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数