Невозможно вставить ключи и значения на карту

Я пытался вставить ключ и значения следующим образом, но получаю сообщение об ошибке:

ошибка: нет соответствующего конструктора для инициализации Edge

Я использую С++17.

Это моя программа:

#include <iostream>
#include <string>
#include <map>

struct Edge
{
    int v1{};
    int v2{};

    Edge (int v1, int v2)
    :v1{v1}, v2{v2}
    {
    }

};

int main()
{
    std::map<std::string, Edge> mymap;

    mymap["edge1"] = Edge(0,0);
    mymap["edge2"] = Edge(1,1);

    return 0;
}

Я почти уверен, что мой конструктор прав, но любая помощь очень ценится.

Когда вы ссылаетесь на mymap["edge1"], система должна создать заполнитель в этом месте, но у вас нет конструктора по умолчанию. Возможно, вы захотите использовать emplace.

Tim Roberts 10.05.2024 02:48

Да, это исправлено после того, как я добавил Edge() = default;, очень странно, потому что в учебнике, которому я следую, преподаватель даже не объявляет никаких конструкторов. Возможно, он использует современную версию C++20, я не уверен.

tadm123 10.05.2024 02:54

Конструктор по умолчанию создается для вас компилятором тогда и только тогда, когда вы не определили никаких других конструкторов. Как только вы объявили Edge (int v1, int v2), компилятор будет использовать только указанный вами конструктор (и конструктор синтезированной копии, но это доставит вам проблемы в другом месте)

user4581301 10.05.2024 02:57

@ tadm123 Не объявлять здесь какие-либо конструкторы было бы эквивалентно определению только конструктора по умолчанию. Так что это сработает. Поскольку вы добавили пользовательский конструктор, конструктор по умолчанию теперь не создается компилятором неявно. Отсюда и ошибка.

yeputons 10.05.2024 02:57

@ChrisMM Мне нравится этот. он настолько стар, что в ответе, получившем наибольшее количество голосов, цитируется оригинальная документация STL.

user4581301 10.05.2024 02:59

Примечание: в большинстве случаев вам не нужен конструктор по умолчанию, потому что вам нужно, чтобы параметры экземпляра имели какой-либо смысл. Лучше принудительно выполнить полную инициализацию объекта, чем добавлять тесты по всему коду, чтобы убедиться в жизнеспособности экземпляра перед его использованием. Edge достаточно прост, и вы можете (и сделали) инициализировать по умолчанию все члены разумными значениями, но даже в этом случае идеологически вам может не понадобиться конструктор по умолчанию, поскольку он отправляет неправильное сообщение пользователям, которые могут начать работать [0,0] созданные по умолчанию экземпляры и стреляют себе в ногу.

user4581301 10.05.2024 03:13
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  • Как было отмечено, в вашем коде отсутствует вызов emplace():
#include <iostream>
#include <string>
#include <map>

struct Edge
{
    int v1{};
    int v2{};
    Edge() = default;
    Edge(int v1, int v2) : v1{v1}, v2{v2} {}
};

int main()
{
    std::map<std::string, Edge> mymap;

    mymap.emplace("edge1", Edge(0, 0));
    mymap.emplace("edge2", Edge(1, 1));
    mymap.emplace("edge2", Edge(2, 2));
    mymap.emplace("edge3", Edge(3, 3));

    for (const auto &pair : mymap)
    {
        std::cout << pair.first << " " << pair.second.v1 << " " << pair.second.v2 << std::endl;
    }
    return 0;
}

Примечание:

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

С другой стороны, Emplace() создает новый Edge «на месте» и позволяет избежать необходимости создавать временный объект и копировать или перемещать его, что немного более эффективно.

Полезная ссылка:

Обзор методов вставки/размещения std::map в C++17

Другие вопросы по теме