0

I was writting some class that map specific multidimensionnal array to unidimensionnal array (like 2D array N by M size is like a 1D array NM size you know, and then you can accees the cell [n, m] through [n+mN]). And it was quite boring since I must handle any multidimensional array (forced to copy/paste many times the class definition).

And I found something that could be great in my case: variadic template function. I would like to have my constructor and accessors using variadic template so my accessors can use any number of parameters (2 for 2D array, 3 for 3D array...) and same for my constructor, since I need to save the size in each dimension (N, M, ...) and multiply then to have the size of my unidimentionnal array.

The problem is that I don't know how to do that :( Every examples I found relies on two functions, one with one parameter of type T and another one with one parameter of type T and the Args... args).

Is it possible in one function ? Without recursion or so ? I gave you what I've made so far:

template <typename T, typename... Args>
T returner(T v, Args... args){
    return v;
}

template <typename T>
class Array{

    public:
    int* dim; //contain the size of each dimension
    T* array; //the actual array

    template<typename... Args>
    Array(Args... args){
        constexpr int size = sizeof...(Args);
        dim = new int[size];
        for(int i=0; i<size; i++)
            dim[i] = returner(args...);
            /*dim[0] should be equal to the first argument, dim[1]
            should be equal to the second argument and so on */
    }
};

int main(){
    Array<int>(2,2,2); // meant to be a 3D array, 2cells in each dimension
    return 0:
}

Obviously, "returner" always return the first argument and I understand why, but the only solution I see it to pass the dim array as a parameter and I would like to not do that. Is there a solution ??

PS: I could do that with classical variadic function, like in C, but it would be quite bad in performance :(

Rama
  • 3,222
  • 2
  • 11
  • 26
Viridya
  • 640
  • 5
  • 13
  • 1
    Could you show us an example where you try to create an `Array` (what do you pass as `Args...` typically?)? Because I don't understand what you are trying to do here... – Holt Jan 26 '17 at 13:32
  • I edited my message, hoping it answers your questions. – Viridya Jan 26 '17 at 13:35

1 Answers1

2

This should do what you want (if I understood correctly):

template <typename T>
class Array{

    public:
    int* dim; //contain the size of each dimension
    T* array; //the actual array

    template<typename... Args>
    Array(Args... args){
        constexpr int size = sizeof...(Args);
        dim = new int[size]{args...};
    }
};

But you'd better use std::vector instead of raw pointers - It would save you a lot of troubles:

template <typename T>
class Array{

    public:
    std::vector<int> dim; //contain the size of each dimension
    std::vector<T> array; //the actual array

    template<typename... Args>
    Array(Args... args) : dim{args...} {

    }
};
Holt
  • 36,600
  • 7
  • 92
  • 139
  • Yeaaah :) Thanks, didnt thought i would initialize an array this way actually... thanks ;) – Viridya Jan 26 '17 at 13:39
  • @Viridya You should probably use `std::vector` here for both `dim` and `array`, it would save you a lots of trouble. – Holt Jan 26 '17 at 13:40
  • @Viridya Is this really what you want? I took your question to mean if you use `Array(2,2,2)` then the size should be 8, not 3 correct? – NathanOliver Jan 26 '17 at 13:41
  • @NathanOliver Size of `array` is 8 (but not taken into account in my question since not asked in the question), but here I am initializing `dim` which should contain `{2, 2, 2}` (if I understood correctly). – Holt Jan 26 '17 at 13:42
  • Actually, I am using vector, but I was in an ... experience phase let's say, so I wanted to know how to do it with most basic type if I can say so. Thanks again. – Viridya Jan 26 '17 at 13:43
  • Indeed, size of "array" is 8, but i can loop over "dim" to get this size (reduction, or if these another way to do so ?). – Viridya Jan 26 '17 at 13:43
  • Oh. Misread, You initialize an array that holds the dimensions. You left the initializing of `array` to the user to do from polling `dim`. – NathanOliver Jan 26 '17 at 13:44
  • 1
    @Viridya You can loop, or `std::accumulate(std::begin(dim), std::end(dim), 1, std::multiplies<>{})` (assuming you are using `std::vector`). – Holt Jan 26 '17 at 13:46
  • Thanks again Holt, I was looking to see how to pass the "multiplication operator", I tried "operator*" but obviously it didnt work :) However, can you explain why you use "begin(dim)" instead of "dim.begin()" ? – Viridya Jan 26 '17 at 13:51
  • 1
    @Viridya In some cases it is more generic to use `begin(dim)` (without `std::` actually), so that the code works if `dim` is a standard container, a raw array (`int [4]`), or a user defined container with a `begin` function. In this case, it does not change anything ;) See http://stackoverflow.com/questions/26290316/difference-between-vectorbegin-and-stdbegin. – Holt Jan 26 '17 at 13:53