Как можно сохранить список строк в контексте constexpr? - PullRequest
4 голосов
/ 16 мая 2019

Я конвертировал эти таблицы строк документации (как черты типа, такие как система) для некоторых классов объектов домена, пока не наткнулся на эту проблему. Позже я планировал проверить во время компиляции, была ли написана документация для этих специальных членов (в качестве причины, по которой я хотел бы получить ее во время компиляции). Я создал небольшой пример для демонстрации:

https://godbolt.org/z/3dX3-e

#include <initializer_list>

struct CStr {
    struct M {
      const char* name;
      const char* val;
    };

  constexpr CStr(const std::initializer_list<M>& str) : str_(str) {
  };

  std::initializer_list<M> str_;
};

constexpr CStr cstr_test{ { {"key", "val"} } };

int main() {
  return cstr_test.str_.begin()->name[0];
}

В основном 3 основных компилятора, похоже, по-разному относятся к этому случаю, этот , по-видимому, работает на более старом , но не может скомпилироваться при переходе на последнюю версию 9.1 (например, строку cstr_test не является постоянным выражением). На ( и на тот, который заинтересован в ) initializer_list получает правильный размер, но временный не сохраняется на выходе. отказался от компиляции из-за временного создания. Эта последняя вещь кажется намеком, и я подозреваю, что это может происходить и с , но без сообщения об ошибке.

Пример можно исправить, если изменить std::initializer_list<M> на M.

Соответствующим разделом из справочника может быть:

Базовый массив - это временный массив типа const T [N], в котором каждый элемент инициализируется копией (за исключением того, что сужающие преобразования недопустимы) из соответствующего элемента оригинала список инициализаторов. Время жизни базового массива такое же, как любой другой временный объект, кроме инициализации Объект initializer_list из массива продлевает время жизни массив точно так же, как привязка ссылки к временному (с тем же исключения, например, для инициализации нестатического члена класса). базовый массив может быть размещен в постоянной памяти.

Как создать список объектов, содержащих строки, во время компиляции?

Ответы [ 2 ]

1 голос
/ 16 мая 2019

std::initializer_list не следует использовать в качестве хранилища.

Так что в вашем случае хранение должно быть сделано за пределами класса. Для этого можно использовать обычный C-массив или std::array.

Тогда ваш класс может просто просмотреть эти данные.

C ++ 20 обеспечивает std::span.

До C ++ 20 вы могли бы сделать что-то вроде:

struct CStr {
    struct M {
        const char* name;
        const char* val;
    };

    constexpr CStr(const M* data, std::size_t size) : data(data), size(size) {}

    const M* begin() const { return data; }
    const M* end() const { return data + size; }

    const M* data;
    std::size_t size;
};

 constexpr CStr::M data[]{ { {"key", "val"} } };

 constexpr CStr cstr_test(data, 1);

int main() {
  return cstr_test.begin()->name[0];
}
0 голосов
/ 16 мая 2019

Это немного другой подход (IMO, ваш пример слишком сложен), но C ++ 17 вводит std::string_view, так что это может быть выполнено простым способом без дополнительных классов.Также, когда вы не знаете, сколько элементов вы можете использовать C-подобный массив:

const constexpr std::pair<std::string_view, std::string_view> str_test[] {
    { "a"sv, "alpha"sv },
    { "b"sv, "beta"sv },
    { "c"sv, "siera"sv },
};

Live demo gcc clang msvc .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...