Надеюсь, это заинтригует некоторых в сообществе.Надеюсь, это не слишком очевидно, потому что я не уверен, что происходит.Я создал шаблон класса variadic с рекурсивным определением, в основном как интересная задача для себя.Вроде как кортеж, этот класс создает unordered_maps of unordered_maps с произвольной глубиной и с произвольными типами ключей на каждом уровне.Таким образом, вы можете, например, создать nested_map<int, std::string, float, int>
и затем установить его с map["fred"][3.4][42] = 35;
Вот код - не слишком сумасшедший.
template<typename T, typename K, typename ... KS> struct nested_map_base : std::unordered_map<K, T>
{
T &operator[](const K &key)
{
// just to verify we get to the bottom of things recursively
std::cout << "base: key = " << key << std::endl;
return this->std::unordered_map<K, T>::operator[](key);
}
};
template<typename T, typename New_K, typename K, typename ... KS>
struct nested_map_base<T, New_K, K, KS ...>
: std::unordered_map<New_K, nested_map_base<T, K, KS...>>
{
nested_map_base<T, K, KS...> &operator[](const New_K &new_key)
{
// just for debugging and to demonstrate that it's working
// for purposes of this question
std::cout << "midway: key = " << new_key << std::endl;
return this->std::unordered_map<New_K, nested_map_base<T, K, KS...>>::operator[](new_key);
}
};
Работает нормально.Запустив следующий код, вы получите ожидаемый результат -
std::cout << "Method1:" << std::endl << std::endl;
nested_map_base<int, std::string, double, int> test_nest;
std::cout << "insert" << std::endl;
test_nest["leonard"][4.8][45] = 111;
std::cout << "retrieve" << std::endl;
int &answer = test_nest["leonard"][4.8][45];
std::cout << "Aanswer should be 111. Answer is " << answer << std::endl << std::endl;
производит -
Method1:
insert
midway: key = leonard
midway: key = 4.8
base: key = 45
retrieve
midway: key = leonard
midway: key = 4.8
base: key = 45
Aanswer should be 111. Answer is 111
Neat.Тогда я подумал, что хотел бы обернуть его во внешний класс, чтобы сохранить приватность реализации, поэтому я просто начал так:Следующий код дает разные результаты -
std::cout << "Method2:" << std::endl << std::endl;
nested_map<int, std::string, double, int> test_nest;
std::cout << "insert" << std::endl;
test_nest["leonard"][4.8][45] = 111;
std::cout << "retrieve" << std::endl;
int &answer = test_nest["leonard"][4.8][45];
std::cout << "Answer should be 111. Answer is " << answer << std::endl << std::endl;
Он производит это -
Method2:
insert
midway: key = leonard
midway: key = 4.8
base: key = 45
retrieve
midway: key = leonard
midway: key = 4.8
base: key = 45
Answer should be 111. Answer is 0
Рекурсивное мета-программирование с вариационным шаблоном заполнено ловушками, и есть причины, по которым вещи не слишком оборачиваютсячасто, так что я не был шокирован, что завернутый не работал, но что меня удивило, так это то, КАК это не сработало.Как и ожидалось, он повторился вплоть до std::unordered_map
, который содержал тип терминальных данных.В отладчике ссылка на int была восстановлена из карты терминала, и она была установлена в 111 в простом тестовом коде.Тот факт, что вы видите повторение ключей во второй раз, указывает на то, что процесс поиска, похоже, тоже работает, но ссылка была на нулевое значение типа int.Любопытно.
Я копаю глубже в отладчике, чтобы увидеть, например, фактическое значение адреса установленной ссылки совпадает с той ссылкой, которая использовалась для получения.Единственный способ, которым они могут отличаться, я думаю, если бы, например, предпоследний рекурсивный слой возвращал временную температуру конечного слоя вместо ссылки на тот, что в структуре данных.Или, может быть, в завернутом случае они все временные, вместо ссылок ... что-то в этом роде, но если упаковка такая легкая, это кажется невозможным.Поэтому я добавлю комментарии, если узнаю больше, но я решил высказать это сообществу, чтобы узнать, есть ли что-то, что могут различить различные группы глаз при проверке.