Время компиляции данных структур данных, отличных от массивов? - программирование
Подтвердить что ты не робот

Время компиляции данных структур данных, отличных от массивов?

В С++ вы можете сделать это:

static const char * [4] = {
   "One fish",
   "Two fish",
   "Red fish",
   "Blue fish"
};

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

Но что, если я предпочитаю использовать другую структуру данных вместо массива? Например, если бы я хотел, чтобы моя структура данных имела быстрый поиск с помощью ключа, мне пришлось бы сделать что-то вроде этого:

static std::map<int, const char *> map;

int main(int, char **)
{
   map.insert(555, "One fish");
   map.insert(666, "Two fish");
   map.insert(451, "Red fish");
   map.insert(626, "Blue fish");

   [... rest of program here...]
}

... который менее элегантен и менее эффективен, так как структура данных карты заполняется во время выполнения, хотя все данные были известны во время компиляции, и поэтому эта работа могла бы (теоретически) быть выполнена.

Мой вопрос: есть ли способ в С++ (или С++ 11) создать структуру данных только для чтения (например, карту), данные которой полностью настроены во время компиляции и, таким образом, предварительно заполнены и готовы использовать во время выполнения, как может быть массив?

4b9b3361

Ответ 1

Не легко, нет. Если вы попытались сделать свой первый пример, используя malloc, очевидно, что он не будет работать во время компиляции. Поскольку каждый стандартный контейнер использует new (ну, std::allocator<T>::allocate(), но мы будем делать вид, что он new пока), мы не можем сделать это во время компиляции.

Это было сказано, это зависит от того, сколько боли вы готовы пройти, и сколько вы хотите отступить, чтобы скомпилировать время. Вы, конечно, не можете этого сделать, используя только стандартные функции библиотеки. Используя boost::mpl, с другой стороны...

#include <iostream>

#include "boost/mpl/map.hpp"
#include "boost/mpl/for_each.hpp"
#include "boost/mpl/string.hpp"
#include "boost/mpl/front.hpp"
#include "boost/mpl/has_key.hpp"

using namespace boost::mpl;

int main()
{
    typedef string<'One ', 'fish'> strone;
    typedef string<'Two ', 'fish'> strtwo;
    typedef string<'Red ', 'fish'> strthree;
    typedef string<'Blue', 'fish'> strfour;

    typedef map<pair<int_<555>, strone>,
        pair<int_<666>, strtwo>,
        pair<int_<451>, strthree>,
        pair<int_<626>, strfour>> m;

    std::cout << c_str<second<front<m>::type>::type>::value << "\n";
    std::cout << has_key<m, int_<666>>::type::value << "\n";
    std::cout << has_key<m, int_<111>>::type::value << "\n";
}

Ответ 2

Если вам нужна карта (или набор), рассмотрите вместо этого, используя двоичное дерево хранящееся в виде массива. Вы можете утверждать, что он правильно упорядочен во время выполнения в отладочных сборках, но в оптимизированных сборках вы можете просто предположить, что все правильно организовано, и затем может выполнять те же виды операций поиска двоичных данных, что и на std:: map, но с базовыми хранилище представляет собой массив. Просто напишите небольшую программу для извлечения данных для вас, прежде чем вставлять их в вашу программу.

Ответ 3

Стоит отметить, что ваша проблема связана с тем фактом, что вы используете карту. Карты часто злоупотребляют. Альтернативным решением для карты является отсортированный вектор/массив. Карты становятся "лучше", чем карты, когда используются для хранения данных неизвестной длины или (и только иногда), когда данные часто меняются.

Функции std:: sort, std:: lower_bound/std:: upper_bound - это то, что вам нужно. Если вы можете сортировать данные самостоятельно, вам нужна только одна функция, lower_bound и данные могут быть const.

Ответ 4

Да, С++ 11 разрешает инициализаторы:

std::map<int, const char *> map = {
  { 555, "One fish" },
  { 666, "Two fish" },
  // etc
};