Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emplace an aggregate in std::vector

Tags:

c++

I tried to initialize the std::vector

std::vector<Particle> particles;

with instances of the simple struct

struct Particle {
    int id;
    double x;
    double y;
    double theta;
    double weight;
};

by using emplace with an initializer list:

num_particles = 1000;
for (int i = 0; i < num_particles; i++)
{
    particles.emplace_back({ i,0.0,0.0,0.0,1 });
}

But I get the error

C2660 "std::vector>::emplace_back": Function doesn't accept one argument

How can I fix that?

like image 933
user1934212 Avatar asked Apr 13 '17 14:04

user1934212


People also ask

What is emplace in vector?

The vector::emplace() is an STL in C++ which extends the container by inserting a new element at the position. Reallocation happens only if there is a need for more space. Here the container size increases by one.

What is emplace back in vector?

std::vector::emplace_backInserts a new element at the end of the vector, right after its current last element. This new element is constructed in place using args as the arguments for its constructor.

What is the difference between emplace and Push_back?

push_back("foo") constructs a temporary string from the string literal, and then moves that string into the container, whereas my_vec. emplace_back("foo") just constructs the string directly in the container, avoiding the extra move.


2 Answers

std::vector::emplace expects an iterator as argument too, because it inserts the element before that iterator's position.

Another problem is that your {i, 0.0, 0.0, 1} initialization doesn't work because it isn't in a context which tells what type it needs to instantiate. The reason there isn't any context is due to emplace and emplace_back member functions having generic parameters.

If you just want to append elements to the vector, use emplace_back.

However, emplace_back depends on the element type having a valid constructor in order to work, as the element is initialized through parentheses. That changed in C++20, which now allows aggregate-initialization through parentheses without the need to define a valid constructor.

So, up until C++17, your example would be changed to:

for (int i = 0; i < num_particles; ++i)
    particles.push_back({i, 0.0, 0.0, 1});

And in C++20 and later, you may do this instead:

for (int i = 0; i < num_particles; ++i)
    particles.emplace_back(i, 0.0, 0.0, 1);
like image 162
Mário Feroldi Avatar answered Sep 28 '22 19:09

Mário Feroldi


You have several issues with your code:

  • Emplace takes an iterator as insertion point, and then a list of values which serve as arguments to a constructor.

  • Your struct must have a constructor which takes the values you pass to emplace.

  • You only have 4 argument values in your code, but your Particle struct has 5 fields.

Try this code instead:

struct Particle {
    int id;
    double x;
    double y;
    double theta;
    double weight;

    Particle(int id, double x, double y, double theta, double weight) 
        : id(id), x(x), y(y), theta(theta), weight(weight)
    {
    }
};

Notice the constructor there. And then emplace, for instance in the beginning [just an example which is not inserting at the back (see below)]:

std::vector<Particle> particles;

auto num_particles = 1000;
for (int i = 0; i < num_particles; i++)
{
    particles.emplace(particles.begin(), i, 0.0, 0.0, 1.0, 0.0);
}

As others have noted, if you just want to insert without specifying a specific position in the vector, you can use emplace_back:

std::vector<Particle> particles;

auto num_particles = 1000;
for (int i = 0; i < num_particles; i++)
{
    particles.emplace_back(i, 0.0, 0.0, 1.0, 0.0);
}

This inserts the elements at the end of the vector.

like image 32
odyss-jii Avatar answered Sep 28 '22 19:09

odyss-jii