C std ::vector::emplace_back не компилируется с классом строковых значений

#c #perfect-forwarding

#c #идеальная пересылка

Вопрос:

 /* Item.h */
struct Item {
    std::string name;

    Item(std::string _name) : name( std::move(_name) ) { }
};

/* main.cpp */
/* ... */
const int amount_of_items = val.size();
std::vector<Item> items(amount_of_items);

for( Json::Value::const_iterator itr = val.begin() ; itr != val.end() ;   itr ) {
    items.emplace_back( "item_name" );
}
 

Приводит к:

 /usr/include/c  /8/bits/stl_construct.h:75:7: error: no matching function for call to ‘Item::Item()’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from main.cpp:8: Item.h:8:2: note: candidate: ‘Item::Item(std::__cxx11::string)’   Item(std::string _name) : name( std::move(_name) ) { }   ^~~~ Item.h:8:2: note:   candidate expects 1 argument, 0 provided
 

Я не знаю, почему это не сработает — есть идеи?

Ответ №1:

Проблема в том, что вам нужен конструктор по умолчанию Item для этой последовательности кода. Конструктор по умолчанию отключен, потому что у вас есть пользовательский конструктор для Item .

Вы можете включить его, добавив Item()=defau< .

Кроме того, у вас есть логическая ошибка: std::vector<Item> items(amount_of_items); инициирует items amount_of_items создание конструктивных элементов по умолчанию. Это не то, что вы хотите в соответствии со следующей последовательностью, так как к концу у вас будет вдвое больше элементов.

Вы должны были написать

 std::vector<Item> items;
items.reserve(amount_of_items);
 

Ответ №2:

Это утверждение:

 std::vector<Item> items(amount_of_items);
 

требуется конструктор по умолчанию для Item , поскольку вы попросили компилятор заполнить массив сконструированными по amount_of_items умолчанию Item s .

Вместо этого вам нужно просто написать:

 std::vector<Item> items;
 

поскольку emplace_back массив будет увеличиваться по мере необходимости.

Обратите внимание, что вы можете вызвать items.reserve , если хотите заранее зарезервировать место для своих Item файлов.

Ответ №3:

При вызове std::vector конструктора:

 std::vector<Item> items(amount_of_items);
 

Вызывается конструктор по умолчанию содержащегося типа: Item . Вы должны либо определить конструктор по умолчанию:

 Item() = default
 

Или используйте один из других std::vector конструкторов, у которых нет этого требования:

 std::vector<Item> items(amount_of_items, {""});
 

Ответ №4:

У вас нет конструктора по умолчанию в вашей структуре, потому что вы добавили конструктор не по умолчанию. Вы могли бы добавить обратно свой конструктор по умолчанию.

Но строка ошибки на самом деле является вашей инициализацией (количество элементов), это попытка по умолчанию сконструировать item s с помощью c’tor по умолчанию.

Поэтому я рекомендую вам добавить c’torпо умолчанию:

     Item() = defau<
 

Или инициализация со строкой:

 std::vector<Item> items(num_items, std::string(""));
 

Также ваш конструктор ‘move’ должен использовать r-value ref amp;amp; (и, вероятно, также явно, поскольку он имеет только один параметр):

     Item() = defau<

    //             here
    //               V
    explicit Item(std::string amp;amp;_name) : name( std::move(_name) ) { }