С++ 17 синтаксический анализ строки constexpr

Извините, что это будет длинный пост, но я чувствую, что вам нужен весь код, чтобы узнать, что происходит.


Итак, я экспериментировал с идеей компиляции временной строки для анализатора структуры данных. Подумайте о чем-то вроде регулярного выражения, где строка "компилируется" в структуру данных во время компиляции, но выполняется во время выполнения (при условии, что входная строка является константой, конечно). Но я столкнулся с проблемой, что я не совсем понимаю, что случилось:

В принципе, мой дизайн - парсер с двумя проходами:

  • Передача 1: определение количества "кодов операций" во входной строке
  • Pass 2: возвращает массив, размер которого определяется Pass 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!
}

Все идет нормально!

Проблема возникает, когда я пытаюсь просто обернуть эти 2 строки в функцию: -/. Я не понимаю, почему тот же самый точный код работает в 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:

Ответ 1

Пусть это уменьшит:

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. Как только вы передаете что-то через параметр функции, constexprness потеряется.