У меня есть (сторонний) класс, который не подлежит копированию. Я хотел бы инициализировать их массив. Вот моя лучшая попытка:
#include <array>
class Thing
{
public:
explicit Thing(int) {}
Thing(const Thing&) = delete;
};
int main()
{
std::array<Thing, 1> things{{{100}}}; // error here
};
GCC 4.7.2 говорит:
ошибка: преобразование в ‘std :: array :: value_type
{aka Thing} ’из списка инициализаторов будет использовать явный конструктор
«Вещь :: Thing (интермедиат)»
Хорошо, но это именно то, что я хочу — использовать явный конструктор. Как я могу выразить это? Если я на самом деле вызываю конструктор сам, то получаю ошибку об удалении конструктора копирования. И я не могу использовать std::move()
потому что вещь не подвижна (и я не могу ее изменить).
Единственная альтернатива, которую я нашел, https://stackoverflow.com/a/15962814/4323 но это нежелательно, потому что это куча лишнего кода, плюс мне нужно приводить «хранилище» везде, где я его использую (или хранить отдельный указатель на него, что добавляет косвенность, которую я не хочу).
Я хочу решение, которое дает максимальную производительность при использовании вещей без большого количества отвратительного шаблона.
И снова C ++ 17 гарантированная копия elision приходит на помощь: выражение как Thing{100}
больше никогда создает объект, но просто указывает как какой-то другой объект (ваш элемент массива) должен быть создан.
Я попытался добавить ctor по умолчанию и оператор присваивания перемещения, немного изменил инициализацию и он компилируется:
#include <array>
class Thing
{
public:
explicit Thing(int) {}
Thing(const Thing&) = delete;
Thing(Thing&&) = default;
Thing& operator=(Thing&&) = default;
};
int main()
{
std::array<Thing, 1> things {{ Thing(100) }}; // error gone
}
РЕДАКТИРОВАТЬ: я пропустил «стороннюю» часть. Извините, если это не поможет 🙂
Вы можете использовать std::vector
:
std::vector<Thing> things;
things.reserve(1);
things.emplace_back(100);
или только для одного элемента boost::optional
:
boost::optional<Thing> thing;
thing.emplace(100);