у меня есть std::map<std::pair<std::string, std::string>, float>
это занимает слишком много памяти, и чтобы использовать меньше памяти, я решил отобразить уникальные строки в целые числа (например, std::map<std::string, int>
где каждая новая уникальная строка отображается на текущий size()
карты) и использовать эти целочисленные значения в качестве парных ключей к карте (например, std::map<std::pair<int, int>, float>
).
Вместо int
Я хочу использовать станд :: Карта :: size_type:
using map_index = std::map::size_type;
std::pair<map_index, map_index> key;
Конечно, это не компилируется, потому что мне нужно предоставить список аргументов для карты:
vector.cc:14:19: error: invalid use of template-name `std::map' without an argument list
using map_index = std::map::size_type;
И это (в теории) это то, что я пытаюсь достичь:
using map_index = std::map<std::string, map_index>::size_type;
что дает следующую (ожидаемую) ошибку компилятора:
vector.cc:15:41: error: `map_index' was not declared in this scope
using map_index = std::map<std::string, map_index>::size_type;
Как правильно заставить компилятор сделать правильный вывод? value_type
для std::map
чья value_type
это свой size_type
?
То, что вы ищете, вообще говоря, невозможно.
Это возможно (хотя и надумано), что std::map<int, long>::size_type
является int
а также std::map<int, int>::size_type
является long
(и аналогично для других целочисленных типов), в этом случае нет никакого возможного способа удовлетворить std::map<int, T>::size_type
являющийся T
,
И наоборот, это может быть std::map<int, T>::size_type
определяется как T
для всех T
в этом случае нет уникального T
удовлетворяя ваше «требование».
Как уже упоминалось в нескольких ответах (и вашей собственной ссылочной ссылке), на практике это вряд ли что-то еще, кроме size_t
,
size_t
должно быть достаточно хорошо для такого случая.
Но если вы настаиваете, вы можете сделать так:
#include <type_traits>
#include <map>
template <class Key, class Value = size_t, size_t depth = 0, class = void>
struct GetSizeType {
using type = typename GetSizeType<Key, typename std::map<Key, Value>::size_type, depth + 1>::type;
};
template <class Key, class Value, size_t depth>
struct GetSizeType<Key, Value, depth, std::enable_if_t<std::is_same_v<Value, typename std::map<Key, Value>::size_type>>> {
using type = typename std::map<Key, Value>::size_type;
};
template <class Key, class Value>
struct GetSizeType<Key, Value, 100, void> {};
int main() {
using X = GetSizeType<int>::type;
return 0;
}
Он будет работать рекурсивно на GetSizeType
рекурсивный вызов остановится на
type
в этом случае) илиstd::map
из которых mapped_type
а также size_type
идентичен (член type
псевдонимы size_type
).Отказ от ответственности: это решение довольно глупо. Мы просто собираемся решить уравнение, неоднократно (обычно один раз) пытаясь создать экземпляр std::map
пока мы не найдем тот, который имеет запрошенный ключ и свой собственный size_type
как ценность.
template <class T>
struct identity {
using type = T;
};
template <class K, class V = char>
struct auto_map {
using map_type = std::map<K, V>;
using type = typename std::conditional_t<
std::is_same_v<
typename map_type::mapped_type,
typename map_type::size_type
>,
identity<map_type>,
auto_map<K, typename map_type::size_type>
>::type;
};
template <class K>
using auto_map_t = typename auto_map<K>::type;
Если метафункция не может найти такую карту, она либо выдает ошибку, потому что type
заканчивается определенным для себя, или нарушает предел рекурсии.
использование std::size_t
, Целое число без знака std::map::size_type
не будет больше чем std::size_t
и на практике будет того же типа.
Если вы хотите быть уверены, заявите это:
static_assert(std::is_same_v<
std::size_t,
std::map<std::string, std::size_t>::size_type
>);
Все реализации C ++ в дикой природе, которые я использовал, используют один и тот же тип размера для всех карт.
Так;
using map_size_type = std::map<int, int>::size_type;
using my_map = std::map<std::string, map_size_type>;
static_assert(std::is_same<map_size_type, my_map::size_type);
это просто вызывает ошибку компиляции, если (разумное) предположение не выполняется.
Единственный способ разорвать круговую зависимость — это использовать определенный тип. Я рекомендую вам просто сделать map_index
быть std::size_t
— C ++ сильно подразумевает это std::size_t
будет назначен на map::size_type
,
Но вы уверены, что size_type
из std::map
зависит от типа ключ / значение?
Если так, я не вижу способа получить это.
Но size_type
не должен зависеть от типа ключ / значение и обычно std::size_t
,
Я предлагаю
using Index0 = typename std::map<std::string, std::size_t>::size_type;
using mapIndex = typename std::map<std::string, Index0>::size_type;
Вы можете проверить, что вы получили правильный тип с
static_assert( std::is_same_v<Index0, mapIndex>, "no right type");