Below is a class that I've defined with a deleted copy constructor and copy assignment operator. This is the only assumption that has to be made.
class MyClass
{
public:
explicit MyClass(int i) : i(i) {}
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
MyClass(MyClass&& other) :
i(std::move(other.i))
{}
MyClass& operator=(MyClass&& other) {
i = std::move(other.i);
return *this;
}
private:
int i;
};
The goal is then to add my class to a std::vector at compile time.
int main()
{
std::vector<MyClass> v{MyClass{0}, MyClass{1}, MyClass{2}};
return 0;
}
My compiler is telling me that the STL requires the use of my deleted copy constructor MyClass::MyClass(const MyClass&)
but is there any way around this?
I am already aware of a possible way to add values at runtime but the below is a poor solution in my opinion because I've lost the compile time check.
int main()
{
std::vector<MyClass> v;
v.emplace_back(MyClass{0});
v.emplace_back(MyClass{1});
v.emplace_back(MyClass{2});
return 0;
}
My compiler is telling me that the STL requires the use of my deleted copy constructor
MyClass::MyClass(const MyClass&)
but is there any way around this?
No, you can't.
initializer_list
creates a hidden array for you, which is declared const
, roughly evaluated like this:
// pseudo code
const MyClass __arr[3] = { MyClass(1), MyClass(2), MyClass(3) };
std::vector<MyClass> v{ std::initializer_list<MyClass>{ __arr, __arr + 2 } };
If you want to avoid copying, you'll have to stick to emplace_back
like you said.
I am already aware of a possible way to add values at runtime ...
By the way, your example is not the proper way to use emplace_back
:
std::vector<MyClass> v;
v.emplace_back(MyClass{0});
v.emplace_back(MyClass{1});
v.emplace_back(MyClass{2});
You're still creating MyClass
and then move it to v
, which is quite a common mistake when using emplace
-ish functions.
What you really wanted to do is probably as follows:
v.reserve(3);
v.emplace_back(0);
v.emplace_back(1);
v.emplace_back(2);
This way you're avoiding accidentally invoking move constructor, and just constructing the object at the right place only once with no move, and no copy.
The goal is then to add my class to a
std::vector
at compile time.
If you want to create an array at compile time, use std::array
instead.
std::array
is exactly designed for that purpose:
std::array<MyClass, 3> v = { 1, 2, 3 };