nils
nils

Reputation: 335

C++ template arguments

I have a template that makes a vector. The default constructor assigns n identical valued elements. The second constructor makes a vector with given arguments. Due to the fact that the second constructor uses the default constructor to define the vector, I can only give arguments about how many elements will be in this vector and what is their value.

    public:
      vector<float> coords;
      Vector<n> (){
      coords.assign(n, 0.0);
      }
      Vector<n> (vector<float> crds){
          coords.assign(crds.size(),0.0);
}   

Ideally the second constructor should take crds and check it size. Then assign zeros as many times as the size of crds. It works well if the size is 2. But if the size is more or less than 2 it gives out errors.

If I get this working then I would insert every value in crds and pop the unnecessary zeros. But at the moment I can't figure out another solution. + I didn't find any other vector stl function that would suit me better than assign.

The code with which I check the result is

    Vector<2> v2 (vector<float>(2,3)); 

Upvotes: 0

Views: 249

Answers (2)

Robᵩ
Robᵩ

Reputation: 168876

This does what I think you are asking for. The code complexity in the 2nd constructor ensures that we don't copy extra values in, just to erase them.

#include <vector>
#include <algorithm>
#include <cassert>

// untested
template <std::size_t n>
struct Vector {
  std::vector<float> coords;
  Vector() : coords(n, 0.) {}
  Vector(const std::vector<float>& crds)
    : coords(crds.begin(),
        crds.begin()+std::min(n, crds.size())) {
    // resize() extends coords with 0.0 values
    coords.resize(n);
  }
};

int main () {
  std::vector<float> v(3);
  Vector<6> V(v);
  assert(V.coords.size() == 6);
}


EDIT: responding to explained requirements:

#include <vector>
#include <algorithm>
#include <cassert>

// untested
template <std::size_t n>
struct Vector {
  std::vector<float> coords;
  Vector() : coords(n, 0.) {}
  Vector(const std::vector<float>& crds)
    : coords(crds) { }
};

int main () {
  Vector<6> V1;
  Vector<6> V2(std::vector<float>(3, 2.));
  Vector<6> V3(std::vector<float>(10, 3.));
  assert(V1.coords.size() == 6);
  assert(V2.coords.size() == 3);
  assert(V3.coords.size() == 10);
}


EDIT: Responding to requirement for initializer list.

If your compiler provides c++11 features, you can initialize either std::vector or Vector from a list of values, using std::initializer_list.

#include <vector>
#include <algorithm>
#include <cassert>
#include <initializer_list>

// untested
template <std::size_t n>
struct Vector {
  std::vector<float> coords;
  Vector() : coords(n, 0.) {}
  Vector(const std::vector<float>& crds)
    : coords(crds) { }
  Vector(std::initializer_list<float> list)
    : coords(list) {}

};

int main () {
  Vector<6> V1;
  Vector<6> V2(std::vector<float>(3, 2.));
  Vector<6> V3(std::vector<float>(10, 3.));
  Vector<6> V4(std::vector<float> ({1, 2, 3, 4}));
  Vector<6> V5({1, 2, 3, 4});
  assert(V1.coords.size() == 6);
  assert(V2.coords.size() == 3);
  assert(V3.coords.size() == 10);
  assert(V4.coords.size() == 4);
  assert(V5.coords.size() == 4);
}

Upvotes: 2

If I understand correcly what you want to do, simply using standard vector constructors should do what you want:

#include <vector>

template <int N>
class Vector {
public:
  std::vector<float> coords;

  Vector ()
    : coords(N, 0.0f)
  {}

  Vector (const std::vector<float> & crds)
    : coords(crds)
  {}
};

But, as emphasized by others in the comments, this seems to be poorly designed (in particular, I fail to understand why the role of N in both constructors is so asymmetric)

Upvotes: 0

Related Questions