std :: map :: size_type для std :: map, у которого value_type свой собственный size_type - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть std::map<std::pair<std::string, std::string>, float>, который занимает слишком много памяти, и чтобы использовать меньше памяти, я решил отобразить уникальные строки в целые числа (например, std::map<std::string, int>, где каждая новая уникальная строка отображаетсяк текущей size() карты) и используйте эти целочисленные значения в качестве парных ключей карты (например, std::map<std::pair<int, int>, float>).

Вместо int я хочу использовать std :: map :: 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?

Ответы [ 7 ]

0 голосов
/ 22 ноября 2018

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

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

0 голосов
/ 22 ноября 2018

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

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

0 голосов
/ 22 ноября 2018

Используйте 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
>);
0 голосов
/ 22 ноября 2018

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

0 голосов
/ 22 ноября 2018

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).
0 голосов
/ 22 ноября 2018

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

0 голосов
/ 22 ноября 2018

Но вы уверены, что 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");
...