C++ template class with argument copy constructor - c++

I have a c++ generic class that looks like this:
template <class T, int N> class TwoDimArray{
private:
T tda_[N][N];
int n_;
public:
TwoDimArray(T tda[][N]){
..
}
~TwoDimArray(){
..
}
..
}
How would I write a copy constructor that I will be able to call somehow like this:
int a1[][2] = { 1, 2, 3, 4 };
TwoDimArray <int, 2> tdm1(a1);
TwoDimArray tdm1Copy (tmd1); // or whatever the correct form is
I hope I was clear.

You have lots of typos in your code, but declaring a copy constructor is simple:
TwoDimArray(const TwoDimArray& rhs){/*implement it here*/}
The copy constructor is part of a template class, so you must specify the template type when copying
TwoDimArray<int, 2> tdm1Copy (tdm1); // specify <int,2> as the type
or use auto
auto tdm1Copy(tdm2);
Full working example below:
#include <iostream>
template <class T, int N> class TwoDimArray {
private:
T tda_[N][N];
int n_;
public:
TwoDimArray(T tda[][N]) {
// implement
}
~TwoDimArray() {
// implement
}
TwoDimArray(const TwoDimArray& rhs) // don't really need this
{
// implement
}
};
int main()
{
int a1[][2] = { 1, 2, 3, 4 };
TwoDimArray <int, 2> tdm1(a1);
TwoDimArray<int, 2> tdm1Copy (tdm1); // specify <int,2> as the type
}
Unless you are doing this for a homework or learning purposes, just use std::vector<std::vector<T>> to "simulate" a 2-D array.
Additional remark: Since your class contains an array (and not a pointer, they are not the same), you don't need a copy constructor. The default copy constructor does it for you, i.e. copies the array element by element. So, just get rid of the copy constructor altogether and let the compiler generate a default one.

Related

Expand variadic template to array of static members

I've defined a base class template:
template<class actual_class>
class base
{
public:
static const int value;
}
and the definition of value depends on the actual_class tparam.
Next, I have a bunch of derived classes from base, let's call them a and b. Let's also say that a::value = 5 and b::value = 10.
Now, in a method template where I need to access the static values from a parameter pack. I'd like to have them in a vector.
template<class... derived_from_bases>
void foo(irrelevant_class<derived_from_bases...> irrelevant)
{
// std::vector<int> values = { ... }
...
}
For the function called with < a, b > tparams I'd like the values vector to look like this:
std::vector<int> values = {5 /* a::value */, 10 /* b::value */};
Also having an std::array instead of an std::vector would be a nice touch.
Thank you for your help in advance.
For a vector, you just need
std::vector<int> values = { derived_from_bases::value... };
If you have C++17, you can get a std::array the same way like
std::array values = { derived_from_bases::value... };
and CTAD will deduce the type and size of the array for you. If you do not have C++17, then you can use
std::array<int, sizeof...(derived_from_bases)> values = { derived_from_bases::value... };

2D Std::vector of a given class

I'm trying to use a vector to store x and y coordinates of certain data in my vector. I assumed the following would work but that is not the case. I have spent a lot of time searching hoping to get it to work but in vain. I appreciate any help whatsoever.
class A {
public:
A(size_t x, size_t y); //ctor
};
If I want to create a vector of type class A, so 2D, why is
std::vector<A> vec(10); not working?
void count(size_t x, size_t y) {
vec.at(x,y);
}
ERROR: error: no matching function for call to ‘std::vector<Board>::at(size_t, size_t&)
note: candidate expects 1 argument, 2 provided
Since class A's constructor has 2 variables, shouldn#t my vector of type A take 2 variables as well?
If not, what is the correct way of getting a 2d vector of class A such that I can call the .at()-function at x,y and get whatever is stored there?
This vector overload:
std::vector<A> vec(10);
makes 10 copies of type A by calling A's default constructor. Since you didn't provide a default constructor an error occurs. Provide the default constructor:
class A {
public:
A() = default;
};
int main() {
std::vector<A> v(10);
}
or use an appropriate constructor as a second parameter:
class A {
public:
A(size_t x, size_t y) {
// your code
}
};
int main() {
std::vector<A> v(10, A(1, 2));
}
That being said, don't confuse the vector of vectors:
std::vector<std::vector<T>> v;
with a simple constructor taking two parameters or a simple class having two data members.

Emplacement-like construction for std::vector

Imagine I want to construct a fixed-size std::vector of objects without move or copy constructors, such as std::atomic<int>. In this case the underlying std::atomic class has a 1-arg constructor which takes an int, as well as a default constructor (which initializes the value to 0).
Using the initializer_list syntax like std::vector<std::atomic<int>> v{1,2,3} doesn't work, because the arguments are first converted to the element type T of the vector as part of the creation of the initializer_list and so the copy or move constructor will be invoked.
In the particular case of std::atomic<int> I can default-construct the vector and then mutate the elements after:
std::vector<std::atomic<int>> v(3);
v[0] = 1;
v[1] = 2;
v[2] = 3;
However, in addition to being ugly and inefficient, it isn't a general solution since many objects may not offer post-construction mutation equivalent to what you could get by calling the appropriate constructor.
Is there any way to get the "emplace-like" behavior that I want at vector construction?
A general solution is to make your vector take a custom allocator whose construct method performs the appropriate initialization. In the code below, v uses the MyAllocator<NonMovable> allocator rather than std::allocator<NonMovable>. When the construct method is called with no arguments, it actually calls the constructor with the appropriate argument. In this way, the default constructor can initialize the elements properly.
(For simplicitly, I have made next_value static in this example, but it could just as well be a non-static member variable that's initialized when MyAllocator is constructed.)
#include <stdio.h>
#include <memory>
#include <new>
#include <vector>
struct NonMovable {
NonMovable(int x) : x(x) {}
const int x;
};
template <class T>
struct MyAllocator {
typedef T value_type;
static int next_value;
T* allocate(size_t n) {
return static_cast<T*>(::operator new(n * sizeof(T)));
}
void deallocate(T* p, size_t n) {
::operator delete(p);
}
template <class U>
void construct(U* p) {
new (p) U(++next_value);
}
};
template <class T> int MyAllocator<T>::next_value = 0;
int main() {
std::vector<NonMovable, MyAllocator<NonMovable>> v(10);
for (int i = 0; i < 10; i++) {
printf("%d\n", v[i].x);
}
}
http://coliru.stacked-crooked.com/a/1a89fddd325514bf
This is the only possible solution when you're not allowed to touch the NonMovable class and its constructor may require multiple arguments. In the case where you only need to pass one argument to each constructor, there is a much simpler solution that uses the range constructor of std::vector, like so:
std::vector<int> ints(10);
std::iota(ints.begin(), ints.end(), 1);
std::vector<NonMovable> v(ints.begin(), ints.end());
(Though if you can't afford the extra memory, then you'll have to write a custom iterator, which will be a lot more code.)

Vector of templated objects

I am working on a project that uses templated objects as a vector argument. I must strictly use objects and any primitive types. I'm working on a smaller example to help me grasp the bigger picture.
So far, here is what I have:
#include <iostream>
#include <vector>
using namespace std;
template <class T>
class Thing {
public:
Thing(T type) {
memVar = type;
}
T getMemVar() {
return memVar;
}
private:
T memVar;
};
class U {
public:
U(int i) {
j = i;
}
int getJ () {
return j;
}
private:
int j;
};
int main() {
// your code goes here
vector < Thing <U> > v;
v.push_back(); // idk how to add new elements to this vector.
// I've tried: v.push_back(Thing <U> i(U)),
// v.push_back(U obj(4)), etc etc...
return 0;
}
I don't know how to add elements to this vector.
By example
v.push_back(Thing<U>(4));
If you can compile C++11 or newer, even simpler
v.emplace_back(4)
But, in both cases, you have to modify the constructor of Thing as follows
Thing(T type) : memVar(type) {
}
or add a default constructor in U
U () {
}
because your Thing constructor try to initialize memVar without arguments and next to copy type in memVar

C++ - create new constructor for std::vector<double>?

I have written a custom container class which contains a std::vector<double> instance - works nicely. For compatibility with other API's I would like to export the content of the container as a std::vector<double> copy . Currently this works:
MyContainer container;
....
std::vector<double> vc(container.begin(), container.end());
But if possible would like to be able to write:
MyContainer container;
....
std::vector<double> vc(container);
Can I (easily) create such a std::vector<double> constructor?
You can create an explicit conversion to std::vector<double>:
explicit operator std::vector<double>() const {
return std::vector<double>(begin(), end());
}
Then, std::vector<double> vc(container); will invoke the std::vector<double> move constructor.
Note that conversions that are computationally expensive are generally frowned upon. Therefore, a vector factory function may be a wiser approach:
class MyContainer {
public:
using value_type = double;
// ...
};
template<typename Source>
auto to_vector(Source source) {
return std::vector<typename Source::value_type>(source.begin(), source.end());
}
Then you'd write:
MyContainer container;
// ...
auto vc = to_vector(container);
This is also more generic as it works with anything that has compatible value_type, begin and end members.
Can I (easily) create such a std::vector constructor?
No you can't, since this would require to change the std::vector class declarations.
You can provide a cast operator for MyContainer to std::vector<double> though.
You cannot, and should not, change the API of a class you didn't write yourself. But I think in your case a cast operator would do just fine. For example (this one needs -std=c++11):
#include <iostream>
#include <vector>
struct Foo
{
operator std::vector<double> () const
{
return std::vector<double> { 1, 2, 3 };
}
};
int main()
{
Foo foo;
std::vector<double> bar = foo; // Applies the cast operator defined in Foo
std::cout << bar.size() << std::endl; // Prints "3"
return 0;
}