Подтвердить что ты не робот

Как помещать объект с конструктором без аргументов в std:: map?

Я хочу заменить объект на std::map, конструктор которого не принимает никаких аргументов. Однако std::map::emplace, по-видимому, требует, по крайней мере, одного дополнительного аргумента, кроме ключа. Итак, как я могу перенаправить нулевые аргументы в конструктор?

4b9b3361

Ответ 1

Тип элемента std::map<K, V> на самом деле std::pair<K, V>, поэтому, когда вы размещаетесь на карте, аргументы будут перенаправлены конструктору std::pair. Вот почему вы не можете передать только ключ: std::pair<K, V> не может быть сконструирован из одного аргумента (если только это не другая пара того же типа.) Вы можете передать нулевые аргументы, но тогда ключ будет инициализирован значением, вероятно, не то, что вы хотите.

В большинстве случаев движущиеся значения будут дешевыми (и ключи будут маленькими и скопируемыми), и вы действительно должны просто сделать что-то вроде этого:

M.emplace(k, V{});

где V - отображаемый тип. Он будет инициализирован и перенесен в контейнер. (Этот шаг может быть даже отменен, я не уверен.)

Если вы не можете двигаться, и вам действительно нужно, чтобы V был создан на месте, вы должны использовать кусочный конструктор конструкции...

M.emplace(std::piecewise_construct, std::make_tuple(k), std::make_tuple());

Это приводит к тому, что std::pair создает первый элемент, используя k, а второй элемент использует нулевые аргументы (инициализация значения).

Ответ 3

У меня была такая же проблема, когда мне приходилось создавать объекты std::map из std::mutex. Проблема в том, что std::mutex не является ни копируемой, ни подвижной, поэтому мне нужно было построить ее "на месте".

Принятый ответ не работает для этого случая (M.emplace(k, V{}); требуется, чтобы V был подвижным). И я не хотел использовать сложную и менее читаемую опцию std::piecewise_construct (см. Выше в других ответах).

Мое решение намного проще - просто используйте operator[] - он создаст значение, используя его конструктор по умолчанию и вернет ссылку на него. Или он просто найдет и вернет ссылку на уже существующий элемент без создания нового.

std::map<std::string, std::mutex> map;

std::mutex& GetMutexForFile(const std::string& filename)
{
    return map[filename]; // constructs it inside the map if doesn't exist
}