Я имею:
const unsigned int hash_1 = 0xaf019b0c;
const unsigned int hash_2 = 0xf864e55c;
const unsigned int hash_3 = 0xfaea8ed5;
Хеши прибывают из автоматически сгенерированного заголовка. Эти хеши косвенно связаны с тегами 1, 2, 3. Теги связаны с классами через сгенерированный идентификатор простого времени компиляции. Тем путем я могу GetTag<Class1>()
и получите мой международный тег для Class1.
Моя цель состоит в том, чтобы упростить хеш-> ассоциация тега. Предпочтительно это должно быть сгенерированным временем компиляции и O (1) время доступа. Память в этом случае не является проблемой. Я не могу использовать стороннее программное обеспечение.
Я попробовал следующее:
template<uint32 t> size_t GetTagByHash() { return 0; }
с определенными реализациями как:
template<> size_t GetTagByHash<hash_1>() { return GetTag<Class1>(); }
но такую реализацию трудно использовать с тех пор, если у меня есть локальная переменная uint32 my_hash;
то, что компилятор не может определить то, что оценивает его, имеет во время компиляции затем, компилятор не может разрешить корректную реализацию GetTagByHash()
звонить.
Как я понимаю, ваша проблема в том, как сделать этот поиск со значениями времени выполнения и времени компиляции.
На самом деле у вас два вопроса. Во-первых, какой алгоритм вы хотите использовать для поиска, а во-вторых, как сказать C++, чтобы он был реализован?
Алгоритм для использования - это несколько неочевидный вопрос; у вас есть список эффективно случайных чисел, и вы хотите найти что-то в этом списке и вернуть соответствующий тег. Вероятно, вам нужна какая-то хэш-таблица, но для начала я покажу несколько примеров с чем-то более простым - и, вероятно, лучшим для небольшого числа хэшей: Простой O(N) поиск, в псевдокоде:
if i = N return tag_N
else if i = N-1 ...
...
else if i = 1 return tag_1
else return tag_0
Итак, как вы скажете C++ сделать это? Вы должны создать список всех ваших хэш-тегов и инструкции для этого. Вот простой способ:
template<int i> struct lookup
{
int result(int j) { return 0; }
};
const unsigned int hash_1 = 0xaf019b0c;
template<> struct lookup<1>
{
int result(int j)
{
if (j == hash_1)
return GetTag<Class1>();
return lookup<0>::result(j);
}
};
const unsigned int hash_2 = 0xf864e55c;
template<> struct lookup<2>
{
int result(int j)
{
if (j == hash_2)
return GetTag<Class2>();
return lookup<1>::result(j);
}
};
И так далее. Затем, в конце, вы можете иметь
int hash_lookup(int j)
{
return lookup<last_hash_number>::result(j);
}
Запись всех этих одинаковых определений - это, однако, боль, поэтому лучше позволить C++ сделать это - и, чтобы сделать это, вы должны определить хэши таким образом, чтобы их можно было итерировать. Давайте сделаем это:
template<int> struct hash_tag {
static const int value = 0;
typedef type void;
};
#define SET_HASH(I, VALUE, CLASS) \
template<> struct hash_tag<(I)> \
{ \
static const int value = (VALUE); \
typedef type (CLASS); \
}
SET_HASH(1, 0xaf019b0c, Class1);
SET_HASH(2, 0xf864e55c, Class2);
SET_HASH(3, 0xfaea8ed5, Class3);
// Define a general recursive lookup struct.
template<int i> struct lookup
{
int result(int j)
{
if (j == hash_tag<i>::value)
return GetTag<hash_tag<i>::type>;
return lookup<i-1>::result(j);
}
};
// Make sure the recursion terminates.
template<> struct lookup<0>
{
int result(int) { return 0; }
};
Затем, вы используете это, как и раньше.
Теперь давайте вернемся к первому вопросу - какой алгоритм вы хотите использовать для поиска? Преимущество этого итеративного O(N) поиска в том, что его легко программировать, и он не требует инициализации каких-либо структур данных во время выполнения - вы можете просто вызвать его. Однако, как уже отмечалось, это O(N). Альтернативным вариантом является использование объекта std::map
; вы можете использовать аналогичное рекурсивное определение для его инициализации во время выполнения, а затем использовать его. Это может выглядеть примерно так:
// Make a typedef to save some typing.
typedef std::map<unsigned int, size_t> Map_type;
typedef std::pair<unsigned int, size_t> Map_value;
// Define a recursion to add hashes to the map.
template<int i> struct add_hash
{
void add(Map_type& hashmap)
{
hashmap.insert(
Map_value(hash_tag<i>::value,
GetTag<hash_tag<i>::type>));
add_hash<i-1>::add(hashmap);
}
};
// Make sure the recursion terminates.
template<> struct lookup<0>
{
void add(Map_type&) {}
};
// Now, create a class to initialize the std::map and do lookup.
class Hash_lookup
{
Hash_lookup() { add_hash<last_hash_number>(map_); }
int result(unsigned int j) { return map_[j]; }
private:
Map_type map_;
}
Лично я, вероятно, объединил бы это с вашей идеей GetTagByHash<>
, и дал бы Hash_loop функцию "вычисляемый во время выполнения результат", как я описал, а также функцию "вычисляемый во время компиляции результат", которая принимает аргумент шаблона, а не аргумент функции. Но, в общем, это основная идея для выполнения поиска во время выполнения - вы помещаете значения, которые хотите найти, в набор шаблонизированных классов, которые вы можете рекурсивно итерировать во время компиляции, а затем вы используете эту рекурсивную итерацию для определения функции поиска или инициализации структуры времени выполнения, которую вы можете использовать для выполнения поиска.