std :: map :: size_type для std :: map, у которого value_type свой собственный size_type

у меня есть 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?

4

Решение

То, что вы ищете, вообще говоря, невозможно.

Это возможно (хотя и надумано), что 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,

1

Другие решения

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).
5

Отказ от ответственности: это решение довольно глупо. Мы просто собираемся решить уравнение, неоднократно (обычно один раз) пытаясь создать экземпляр 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 заканчивается определенным для себя, или нарушает предел рекурсии.

4

использование 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
>);
2

Все реализации 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);

это просто вызывает ошибку компиляции, если (разумное) предположение не выполняется.

2

Единственный способ разорвать круговую зависимость — это использовать определенный тип. Я рекомендую вам просто сделать map_index быть std::size_t — C ++ сильно подразумевает это std::size_t будет назначен на map::size_type,

1

Но вы уверены, что 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");
1
По вопросам рекламы [email protected]