Самый простой способ сопоставить индекс со строкой в ​​C++

Требования:

  • Должен уметь использовать строки C, а также строки C++
  • Быстрый
  • Нет карт
  • Нет шаблонов
  • Нет прямого поиска, т. Е. Индекс может быть за пределами допустимого диапазона.
  • Индекс не последовательный
  • Перечисления и строки, содержащиеся в одном файле заголовка
  • Создавайте только то, что вы используете.

Вот что я до сих пор придумал:

- test.hh -

// Generic mapper
// 
// The idea here is to create a map between an integer and a string.
// By including it inside a class we prevent every module which
// includes this include file from creating their own instance.
//
struct Mapper_s
{
   int Idx;
   const char *pStr;
};

// Status
enum State_t
{
   Running = 1,
   Jumping = 6, 
   Singing = 12
};

struct State_s
{
   static const Mapper_s *GetpMap(void)
   {
       static Mapper_s Map[] = 
       {
            { Running,   "Running" },
            { Jumping,   "Jumping" },
            { Singing,   "Singing" },
            { 0,   0}
        };
        return Map;
    };
};

- test.cc -
// This is a generic function 
const char *MapEnum2Str(int Idx, const Mapper_s *pMap)
{
    int i;
    static const char UnknownStr[] = "Unknown";

    for (i = 0; pMap[i].pStr != 0; i++)
    {
        if (Idx == pMap[i].Idx)
        {
            return pMap[i].pStr;
        }
    }

    return UnknownStr;
}

int main()
{
   cout << "State: " << MapEnum2Str(State, State_s::GetpMap()) << endl;
   return 0;
}

Есть предложения, как это улучшить?

Мне кажется, что заголовочный файл выглядит немного загроможденным ...

Для завершения цикла должно быть pMap [i] .IdX! = INT_MAX; Если массив хранится последовательно, вы можете напрямую ссылаться на состояние <= KNOWN_STATE? pMap [состояние-1]: «Неизвестно» при условии, что KNOWN_STATE = 4;

lakshmanaraj 16.12.2008 12:19

Есть еще ограничения? Есть ли причина использовать State_s вместо одной только карты? Можно ли предположить, что карта определена таким образом, что Idx увеличивается?

mweerden 16.12.2008 12:58

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

singpolyma 16.12.2008 23:00
В чем разница между методом "==" и equals()
В чем разница между методом "==" и equals()
Это один из наиболее часто задаваемых вопросов новичкам на собеседовании. Давайте обсудим его на примере.
Замена символа по определенному индексу в JavaScript
Замена символа по определенному индексу в JavaScript
В JavaScript существует несколько способов заменить символ в строке по определенному индексу.
0
3
484
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

I can't do a direct mapping since one application might be feeding me values which are >out of range for my list of strings. A direct lookup into nothingness would be critical.

Поэтому добавьте количество объектов в массив, которые проверяют ваши методы доступа, прежде чем возвращать значение:

struct map {
const char *mapping[] = { "Running", "Jumping", "Singing" };
const int count = 3;
}

или если вы хотите автоматизировать

struct map {
map() { 
  for( count = 0; strlen( mapping[count] ); ++i )
}

const char *mapping[] = { "Running", "Jumping", "Singing", "" };
int count;
}

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

tormod 16.12.2008 12:46

Как насчет Простой способ использовать переменные перечислимого типа как строку в C?

В этом стиле перечисления и строки не только содержатся в одном файле, они также содержатся в одном месте. Вы можете легко расширить фабрику, чтобы принимать больше «столбцов» в SOME_ENUM, в вашем случае вы можете захотеть, чтобы строка не генерировалась из имени, а предоставлялась явно.

Самое быстрое выполнение: построение хеш-таблицы. Поскольку вы знаете индексы заранее, вы даже можете построить идеальная хеш-таблица.

Самый простой в программировании: используйте массивный оператор switch и надейтесь, что компилятор знает, как оптимизировать для целых чисел, не являющихся смежными. По крайней мере, строки будут жить в сегменте .text самого исполняемого файла, поэтому вам не нужно ничего создавать:

// Status
enum State_t
{
   Running = 1,
   Jumping = 6, 
   Singing = 12
};

const char *StateToString(State_t state)
{
  switch(state)
  {
    case Running: return "Running";
    case Jumping: return "Jumping";
    case Singing: return "Singing";
    default: return "ERROR"; 
  }
}

Вы можете скрыть все это внутри макросов (как предлагает ссылка Suma), чтобы это не было WTF.

Ответ принят как подходящий

Вот на чем я остановился. Используя эту технику, все, что вам нужно сделать, это включить файл заголовка. Вы создадите только то, что используете. Вы также можете сохранить идеальную хеш-таблицу вместо просто Idx & pStr. Этот подход не работает в C.

файл: e2str.hh

struct Mapper_s
{
    int Idx;
    const char *pStr;
};

#define ENUM2STR_BEGIN(x) struct x { static const Mapper_s *GetpMap(void) {  static const Enum2StrMap_s Map[] = 
#define ENUM2STR_END      return Map; }; }

const char *MapEnum2Str(int Idx, const Mapper_s *pMap);

файл: mapper.hh

#include "e2str.hh"

ENUM2STR_BEGIN(State_s) 
{
        { Running,   "Running" },
        { Singing,   "Singing" },
        { Jumping,   "Jumping" },
        { 0, 0}
};
ENUM2STR_END;

файл: test.cc

#include "mapper.hh"
int main()
{
   cout << "State: " << MapEnum2Str(State, State_s::GetpMap()) << endl;
   return 0;
}

Другие вопросы по теме