C++ C++;17 constexpr字符串解析
很抱歉,这将是一篇很长的文章,但我觉得您需要所有的代码来查看发生了什么C++ C++;17 constexpr字符串解析,c++,parsing,c++17,constexpr,C++,Parsing,C++17,Constexpr,很抱歉,这将是一篇很长的文章,但我觉得您需要所有的代码来查看发生了什么 所以,我一直在试验编译时字符串到数据结构解析器的想法。想象一下regex,其中字符串在编译时“编译”到数据结构中,但在运行时执行(当然,只要输入字符串是常量)。但我遇到了一个问题,我不太明白到底出了什么问题: 基本上,我的设计是一个2遍的解析器: 第1步:确定输入字符串中有多少“操作码” 过程2:返回一个数组,其大小由过程1决定,并用“操作码”填充 事情是这样的: // a class to wrap string c
所以,我一直在试验编译时字符串到数据结构解析器的想法。想象一下regex,其中字符串在编译时“编译”到数据结构中,但在运行时执行(当然,只要输入字符串是常量)。但我遇到了一个问题,我不太明白到底出了什么问题: 基本上,我的设计是一个2遍的解析器:
- 第1步:确定输入字符串中有多少“操作码”
- 过程2:返回一个数组,其大小由过程1决定,并用“操作码”填充
// a class to wrap string constants
class constexpr_string {
public:
template <size_t N>
constexpr constexpr_string(const char (&s)[N]) : string_(s), size_(N - 1) {}
public:
constexpr size_t size() const { return size_; }
constexpr size_t capacity() const { return size(); }
constexpr size_t empty() const { return size() != 0; }
public:
constexpr char operator[](size_t n) const { return string_[n]; }
private:
const char *string_;
size_t size_;
};
// would have loved to use std::array, but ran into an issue so..
// wrapped in a struct so we can return it
template <class T, size_t N>
struct constexpr_array {
T array[N] = {};
};
struct opcode { /* not relevant */ };
template <size_t N>
constexpr constexpr_array<opcode, N> compile_string(constexpr_string fmt) {
constexpr_array<opcode, N> compiled;
/* fill in compiled_format */
return compiled;
}
constexpr size_t calculate_size(constexpr_string fmt) {
size_t size = 0;
/* calculate size */
return size;
}
#if 0
// NOTE: Why doesn't **This** work?
constexpr int test(constexpr_string input) {
constexpr size_t compiled_size = calculate_size(input);
constexpr auto compiled_format = compile_string<compiled_size>(input);
return 0;
}
#endif
int main() {
// NOTE: when this works...
constexpr char input[] = "...";
constexpr size_t compiled_size = calculate_size(input);
constexpr auto compiled = compile_string<compiled_size>(input);
execute(compiled); // run it!
}
让我们减少这一点:
constexpr void f(int i) {
constexpr int j = i; // error
}
int main() {
constexpr int i = 0;
constexpr int j = i; // OK
}
函数参数从来不是
constexpr
,因此i
在f
中不是一个常量表达式,不能用于初始化j
。一旦你通过一个函数参数传递了一些东西,constexpr属性就丢失了。这听起来确实是正确的:-/当然,我读过一些关于人们使用constexpr
进行编译时解析的巧妙技巧的文章,人们正在做些什么来解决这个问题?一般的解决方法是将值放入模板非类型参数(或其包)中。对于字符串文字来说,这尤其困难,AFAIK在C++20之前需要一个非标准的扩展(仅由GCC和Clang支持)。好的,我认为您的答案基本上是正确的。。。但是您的简化代码不太具有代表性。我现在正在看一些对我来说毫无意义的东西:这是有效的:constexpr size_t Func(constexpr_字符串输入){if(输入[0]='X'){return 1;}return 0;}这不是:constexpr size_t Func(constexpr_字符串输入){constexpr char ch=input[0];if(ch='X'){return 1;}返回0;}constexpr size\u t编译的大小=计算大小(输入)
是有效的,因为input
在这里是constexpr,而calculate\u size(input)
作为一个整体,是一个有效的常量表达式。在calculate_size
内部,它的参数不是constexpr,但这并不能阻止整个函数调用表达式成为constexpr。@t.C.关于“一般的解决方法是将值放入模板非类型参数中”——您不能使用类似constexpr
lambda的[]constexpr{return string“sv;}
?由于这个问题是用c++17标记的,您是否考虑过在实现中使用std::string\u view
std::string_视图
的构建考虑了constexpr
,因此它绝对值得一看@当然是Hugotexeira。我的计划是,一旦我掌握了我所尝试的以我想要的方式工作的核心概念,就切换到string_视图。你有什么理由必须使用string吗?使用操作符或对象表示正则表达式规则(例如kleene星)可能会容易得多。我相信Boost.Spirit就是这么做的。“regex”是用来比喻我想做的事情的。如:字符串->状态->执行状态。我希望有一个很好的方法在编译时完成第一部分。。。看起来这样做有点复杂。你可能会对Ben Deane和Jason Turner的实验性constexpr
JSON解析器感兴趣。他们的实验题为“康斯特普勒一切”。在()和()举行了会谈。是的,但是我建议你看演讲。
constexpr void f(int i) {
constexpr int j = i; // error
}
int main() {
constexpr int i = 0;
constexpr int j = i; // OK
}