C++17 constexpr 字符串解析
C++17 constexpr string parsing
抱歉,这会很长 post,但我觉得您需要所有代码才能了解发生了什么。
所以,我一直在试验将编译时字符串转换为数据结构解析器的想法。想像一个正则表达式,其中字符串在编译时 "compiled" 进入数据结构,但在 运行 时执行(当然只要输入字符串是常量)。但是我 运行 遇到了一个我不太明白问题出在哪里的问题:
基本上,我的设计是一个 2 pass 解析器:
- 第 1 遍:确定输入字符串中有多少 "opcodes"
- Pass 2:return一个数组,其大小由Pass 1确定,并填充"opcodes"
事情是这样的:
// 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!
}
目前一切顺利!
当我尝试将这两行包装到一个函数中时,问题就出现了:-/。
我不明白为什么相同的代码在 main
中有效,但如果我只是尝试传递相同的代码
constexpr
对象到另一个函数,我开始收到关于不是 constexpr
.
的错误
错误信息如下:
main.cpp: In function ‘constexpr int test(constexpr_string)’:
main.cpp:258:55: error: ‘input’ is not a constant expression
constexpr size_t compiled_size = calculate_size(input);
^
main.cpp:259:70: error: no matching function for call to ‘compile_string<compiled_size>(constexpr_string&)’
constexpr auto compiled_format = compile_string<compiled_size>(input);
^
main.cpp:60:45: note: candidate: template<long unsigned int N> constexpr constexpr_array<opcode, N> compile_string(constexpr_string)
constexpr constexpr_array<opcode, N> compile_string(constexpr_string fmt) {
^~~~~~~~~~~~~~
main.cpp:60:45: note: template argument deduction/substitution failed:
让我们减少这个:
constexpr void f(int i) {
constexpr int j = i; // error
}
int main() {
constexpr int i = 0;
constexpr int j = i; // OK
}
函数参数永远不会是constexpr
,所以f
里面的i
不是常量表达式,不能用来初始化j
。一旦通过函数参数传递某些内容,constexpr-ness 就会丢失。
抱歉,这会很长 post,但我觉得您需要所有代码才能了解发生了什么。
所以,我一直在试验将编译时字符串转换为数据结构解析器的想法。想像一个正则表达式,其中字符串在编译时 "compiled" 进入数据结构,但在 运行 时执行(当然只要输入字符串是常量)。但是我 运行 遇到了一个我不太明白问题出在哪里的问题:
基本上,我的设计是一个 2 pass 解析器:
- 第 1 遍:确定输入字符串中有多少 "opcodes"
- Pass 2:return一个数组,其大小由Pass 1确定,并填充"opcodes"
事情是这样的:
// 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!
}
目前一切顺利!
当我尝试将这两行包装到一个函数中时,问题就出现了:-/。
我不明白为什么相同的代码在 main
中有效,但如果我只是尝试传递相同的代码
constexpr
对象到另一个函数,我开始收到关于不是 constexpr
.
错误信息如下:
main.cpp: In function ‘constexpr int test(constexpr_string)’:
main.cpp:258:55: error: ‘input’ is not a constant expression
constexpr size_t compiled_size = calculate_size(input);
^
main.cpp:259:70: error: no matching function for call to ‘compile_string<compiled_size>(constexpr_string&)’
constexpr auto compiled_format = compile_string<compiled_size>(input);
^
main.cpp:60:45: note: candidate: template<long unsigned int N> constexpr constexpr_array<opcode, N> compile_string(constexpr_string)
constexpr constexpr_array<opcode, N> compile_string(constexpr_string fmt) {
^~~~~~~~~~~~~~
main.cpp:60:45: note: template argument deduction/substitution failed:
让我们减少这个:
constexpr void f(int i) {
constexpr int j = i; // error
}
int main() {
constexpr int i = 0;
constexpr int j = i; // OK
}
函数参数永远不会是constexpr
,所以f
里面的i
不是常量表达式,不能用来初始化j
。一旦通过函数参数传递某些内容,constexpr-ness 就会丢失。