c++17 constexpr string parsing

  • A+

Sorry that this will be along post, but I feel like you need all of the code to see what's going on.

So, I have been experimenting with an idea for compile time string to data structure parser. Think of something like a regex, where the string is "compiled" into a data structure at compile time but executed at runtime (so long as the input string is a constant of course). But I've run into an issue that I don't quite understand what's wrong:

Basically, my design is a 2 pass parser:

  • Pass 1: determine how many "opcodes" are in the input string
  • Pass 2: return an array whose size is determined by Pass 1, and filled in with the "opcodes"

Here's what things look like:

// 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! } 

So far so good!

The problem arises when I try to just wrap those 2 lines into a function :-/. I don't understand why the same exact code works in main, but if I just try to pass the same constexpr object to another function, I start getting errors about things not being constexpr.

EDIT Here's the error message:

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: 


Let's reduce this:

constexpr void f(int i) {     constexpr int j = i; // error }  int main() {     constexpr int i = 0;     constexpr int j = i; // OK } 

Function parameters are never constexpr, so i inside f is not a constant expression and can't be used to initialize j. Once you pass something through a function parameter, the constexpr-ness is lost.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: