Reputation: 65
I would like to modernize a small mathematical library using new C++ paradigms (I have a C++17 compiler). In specific, I need to pass an array to a class through constructor.
This is the "classical" old way I used. It works
class Vector {
public:
long double* elements;
public:
Vector(int size, long double *array) {
elements = new long double[size];
for(int i = 0; i < size; i++) {
elements[i] = array[i];
}
};
virtual ~Vector() {
delete []elements;
}
};
int main() {
long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Vector vector = Vector(10, array);
for (int i = 0; i < 10; i++) {
std::cout << vector.elements[i] << std::endl;
}
return 0;
}
So, I tried to change Vector class with what I have understood about variadic templates and parameter pack. It doesn't work
class Vector {
public:
long double* elements;
public:
template<typename... Args>
Vector(Args... args){
constexpr int size = sizeof...(Args);
elements = new long double[size]{args...};
}
};
int main() {
long double array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
Vector vector = Vector(array);
for (int i = 0; i < 10; i++) {
std::cout << vector.elements[i] << std::endl;
}
return 0;
}
The error returned by compiler is
error: cannot convert ‘long double*’ to ‘long double’ in initialization
elements = new long double[size]{args...};
What am I doing wrong? Further, I'm wondering if it is possible to use a std::array instead of raw array, both either inside main method and in Vector class.
Upvotes: 0
Views: 1734
Reputation: 4243
I'm not sure if this answers your question, but I would give you a general advice: I guess you want to encapsulate your own logic into the vector. The standard library vector is very advanced and you should use it, instead of loosing time to write your own low-level code. You could concentrate more on the logic you need.
Your could define your own vector and still use the advantages of the std::vector for constructing your Vector objects. For example with inheritance:
template<typename T>
class Vector : public std::vector<int>
{
// here comes the implementation of your interface.
}
or composition:
template<typename T>
class Vector {
private:
std::vector<T> elems;
}
In the case of composition you'd have to define the constructors you need.
In both cases you could then use your own Vector as follows:
Vector<double> vec1(10); // construct vector with 10 double's each = 0
Vector<double> vec2(10, 5); // construct vector with 10 double's each = 5
Vector<double> vec3{1,2,3,4}; // using initializer list
Vector<double> vec4(somecontainer.begin(), somecontainer.end()); // construct vector by copying elemts from some other container
etc.
As you see with std::vector you'are getting all the benefits you need for constructing your own Vector object.
Upvotes: 1
Reputation: 16404
According to your definition of
template<typename... Args> Vector(Args... args);
You want to use this constructor in this way:
Vector vector = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
It is possible, if you sightly modify your definition of the constructor to:
template<typename... Args>
Vector(Args... args){
constexpr int size = sizeof...(Args);
elements = new long double[size]{static_cast<long double>(args)...};
}
Please note such kind of use is not good practice, you should normally use std
containers and avoid new
operator.
Upvotes: 1
Reputation: 41770
To pass an array like that variadic templates are not the solution. Variadic templates are used to pass N numbers of parameters to a class/function. Yet you are passing only one parameter!
I would suggest you to
I suggest you tu use array references, which are available in all C++ versions:
class Vector {
public:
long double* elements;
public:
template<std::size_t size>
Vector(long double (&array)[size]) {
elements = new long double[size];
for(int i = 0; i < size; i++) {
elements[i] = array[i];
}
};
virtual ~Vector() {
delete []elements;
}
};
By the way, if you can, use vector. I highly doubt this custom vector class is as efficient as std::vector
(no geometric growth or optimized copy and move)
Upvotes: 2