P45 Imminent
P45 Imminent

Reputation: 8591

Using emplacement to construct a vector of matrices of constant size

I have a matrix class (the element type is Y) that has, along with other constructors, the following constructor:

matrixT(
    size_type rows, // The number of rows
    size_type cols  // The number of columns
) :
    boost::numeric::ublas::matrix<Y>(rows, cols)
{
}

(I use boost BLAS for the actual implementation, but that's not relevant here).

I need a std::vector<matrixT> of this (for Y a double), and I know how many elements I need; n, say. I also know all the sizes in advance; all have rows rows and cols columns

I'd like to do something like

std::vector<matrixT> vec(n, std::emplace(rows, cols))

as I'd like to avoid taking deep copies of such matrices. My understanding is I can do something to force the constructor to be called; which is what std::emplace(rows, cols) is there for.

However I can't get the syntax correct. Any ideas? Do I need to use std::initialiser_list?

(If my terminology is incorrect then please feel free to let me know, or edit the question).

Upvotes: 3

Views: 327

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275555

Here is an emplace_n and emplace_create_vector:

template<class... Ts,class...Args>
void emplace_n( std::vector<Ts...>& vec, size_t n, Args&&... args ) {
  if (vec.capacity() < vec.size() + n ) {
    vec.reserve( (std::max)(vec.capacity()*3/2, vec.size()+n) );
  }
  for (size_t i = 1; i < n; ++i) {
    vec.emplace_back(args...);
  }
  if (n)
    vec.emplace_back(std::forward<Args>(args)...);
}

template<class...Ts,class...Args>
std::vector<Ts...> emplace_create_vector( size_t n, Args&&... args ) {
  std::vector<Ts...> retval;
  emplace_n( retval, n, std::forward<Args>(args)... );
  return retval;
}

live example

This lets you create an n-element vector via emplacement, instead of copying.

std::vector<matrixT> vec = emplace_create_vector<matrixT>(n, rows, cols);

and it does so reasonably efficiently.

Every vector copy above will be elided by any acceptable C++ compiler, and no copy or move constructor of matrixT is called.

Upvotes: 2

Bathsheba
Bathsheba

Reputation: 234715

There's no need for std::vector to have such a constructor.

It already provides a method called emplace_back. The arguments of emplace_back should match the arguments of one of your constructors.

vec.emplace_back(rows, cols) called n times will achieve what you want without taking a deep copy of the matrix. You could even reserve vector storage in advance.

(std::initializer list - note the spelling - is used for brace initialisation; a different topic).

Upvotes: 4

Related Questions