Однострочная инициализация объекта C ++ на карте - PullRequest
1 голос
/ 27 мая 2020

Каков правильный способ инициализировать класс и напрямую назначить unordered_map?

#include <string>

#include <unordered_map>
int main() {
  std::unordered_map<std::string, Foo> s;
  // Foo foo{1};
  s["test"] = Foo(1); // this is bad
  return 0;
}

Foo.h

class Foo {
  public:
    Foo(int x)
      : x_(x) {}

  private:
    int x_;
};

Теперь я получаю

main.cpp:19:4: note: in instantiation of member function 'std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Foo, std::hash<std::__cxx11::string>, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, Foo> > >::operator[]' requested here
  s["test"] = Foo(1);
   ^
Foo.h:3:5: note: candidate constructor not viable: requires single argument 'x', but no arguments were provided
    Foo(int x)
    ^
Foo.h:1:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
class Foo {
      ^
Foo.h:1:7: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided

Проблема связана с s["test"] = Foo(1).

Ответы [ 3 ]

6 голосов
/ 27 мая 2020

Элементы на карте должны быть конструктивными по умолчанию, если вы хотите использовать operator[], потому что он по умолчанию создает значение для данного ключа, когда он еще не существует на карте. Либо сделайте свой Foo конструктивным по умолчанию, либо используйте вместо него insert или emplace.

Конструируемый объект по умолчанию Foo:

class Foo {
  public:
    Foo(int x = 0)   // <- can be called without parameters
      : x_(x) {}

  private:
    int x_;
};
4 голосов
/ 27 мая 2020

s["test"] = Foo(1) инициализирует объект по умолчанию в s["test"], а затем скопирует (или переместит) назначит ему из временного объекта Foo, созданного Foo(1).

Это разваливается, потому что Foo не имеет конструктора по умолчанию, поэтому его нельзя инициализировать по умолчанию.

Вы можете использовать один из unordered_map insert, emplace или try_emplace методы, чтобы обойти это. Например:

s.try_emplace("test", 1)

Это создаст новый объект Foo в s с ключом "test" и передаст 1 его конструктору.

0 голосов
/ 27 мая 2020

Если у вас нет конструктора по умолчанию, вам нужно использовать std::map::insert, std::map::emplace или std::map::try_emplace.

Например,

s.emplace(std::make_pair("test", Foo(1)));

или в более простой форме

s.emplace("test", Foo(1));
...