Templated Multi-Dimensional Arrays

I'm trying to experiment with templates and tried to implement templated arrays, something that can be declared like:

Array!(float, 3, 2, 1) myArray;

I've browsed through several implementations of this problem in C++ but I can't seem to convert it to D as I have little experience with the language (with D).

Anyways these are the stuff I tried, unfortunately none of them worked:

1. Compile-Time Functions - to generate code of the format

"DataType[D0][D1]...[Dn] Identifier"

import std.conv;

static string generateArray(D...)(string type, string identifier, D dimensions)
{
    string result = type;

    for(int i = 0; i < dimensions.length; i++)
    {
        result ~= "[" ~ to!(string)(dimensions[i]) ~ "]";
    }

    result ~= " " ~ identifier ~ ";";

    return result;
}

int main(string[] args)
{
    enum deb = generateArray("float", "data", 3, 2, 1);
    pragma(msg, deb);

    return 0;
}

Which I can wrap into a simple Array class

class Array(T, D...)
{
    mixin(generateArray(T, "Data", D));
}

But this code fails with:

./template_recursion.d(10): Error: variable i cannot be read at compile time
./template_recursion.d(18): Error: template instance template_recursion.expandTuple!(int, int, int) error instantiating
./template_recursion.d(18): Error: CTFE failed because of previous errors in expandTuple

2. Recursive Templates - as stated earlier I have seen implementations of this in C++, but I can't seem to transform those statements into something the D compiler accepts.

Variadic Templates in C++

template<class T, unsigned ... RestD> struct array;

template<class T, unsigned PrimaryD > 
  struct array<T, PrimaryD>
{
  typedef T type[PrimaryD];
  type data;
  T& operator[](unsigned i) { return data[i]; }

};

template<class T, unsigned PrimaryD, unsigned ... RestD > 
   struct array<T, PrimaryD, RestD...>
{
  typedef typename array<T, RestD...>::type OneDimensionDownArrayT;
  typedef OneDimensionDownArrayT type[PrimaryD];
  type data;
  OneDimensionDownArrayT& operator[](unsigned i) { return data[i]; }
};

Upvotes: 2

Views: 210

Answers (1)

Colonel Thirty Two
Colonel Thirty Two

Reputation: 26559

First code, using mixins:

dimensions is an AliasSeq (aka TypeTuple, a misnomer because this one contains integers), which can only be indexed with values known at compile time, which your runtime for loop doesn't supply.

You can, however, use a compile-time foreach loop, as such:

foreach(auto dimension; dimensions) {
    result ~= "[" ~ to!(string)(dimensions[i]) ~ "]";
}

Second code, using templates:

template MultiArray(BaseType, Dimentions...) {
    static if(Dimensions.length == 0)
        alias MultiArray = BaseType;
    else
        alias MultiArray = MultiArray!(BaseType[Dimensions[0]], Dimensions[1..$];
}

Upvotes: 3

Related Questions