0

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.

6
  • 1
    Termplates are expanded at compile time, it won't replace array with its initialization list. Commented Jan 26, 2018 at 20:18
  • 1
    Use std::array instead of these awful c-style arrays please! Commented Jan 26, 2018 at 20:19
  • 1
    Using std together with a class named Vector and a variable named vector is probably an extremely poor idea. (See std::vector) Commented Jan 26, 2018 at 20:19
  • 1
    You are using new which is a very poor choice. You also do not obey the rule of zero so your Vector will break in even simple cases. Just use std::vector. Commented Jan 26, 2018 at 20:22
  • @TheDude Ok, it seems like a good idea. In fact, I do not want to use c-style. But, how can I pass a std :: array through constructor without using to loop to initialize the inner std :: array? Does it exist a different way than templates and parametric pack? Commented Jan 27, 2018 at 8:11

3 Answers 3

2

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)

Sign up to request clarification or add additional context in comments.

Comments

1

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.

3 Comments

I like the second approach you used (I prefer incapsulation to inheritance) and the way you create a Vector object passing directly N values to constructor. In my case, since I don't need to add elements to the inner class container after the Vector is constructed, is it possible to use std::array and not std::vector? In both cases, now I am able to delete in my Vector class either the new and the destructor. But, how can I populate the inner Vector class std::array container without using for loop inside constructor but using incapsulation?
std::array is an aggregate type, which means it has no constructors. I've provided you 2 examples for inheritance and composition using std::array with initialization without for loop (when that was your question): wandbox.org/permlink/af2xWXg9AOkm1G1h
Thanks a lot for your further examples! After making some tests (and having some problems with std::array size) I decided to follow your suggestion to use std::vector with incapsulation, as described in main your answer! :)
1

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.

3 Comments

I would like to not use new operator; so std containers are welcome. I'm wondering if it is possible to use std::array inside my Vector class instead: the main ideas are to remove destructor and to not use for loop in constructor to fill the inner std::array container
std::array needs to know the number of elements at compile time, if you put it directly in your class, your class need to have a template parameter for its size. But all in all, why not use std::vector ? It serves all the requirement you mentioned. Normally you don't need to make a class named Vector.
The class is named Vector because I use it incapsulated in 2DVector, 3DVector and 4DVector classes. So Vector would be a general purpose class, then specialized by others. I am asking about std::array because I need just a container that is not able to change its size after it is created and filled. It is not a problem to have a class with a template parameter where I pass the size. Do you think std::vector is better than std::array in this case too?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.