question with compile-time reflection
Zhenya
zheny at list.ru
Sat Mar 9 15:31:34 PST 2013
On Saturday, 9 March 2013 at 23:05:56 UTC, Ivan Kazmenko wrote:
>> this code fails with message:NDimensionalArray.doIndex(Array)
>> if (is(Array _ : NDimensionalArrayType!(T,s),const(int[]) s))
>> cannot deduce template function from argument types
>> !()(int[2u][2u],const(int[]))
>>
>> Tell me please,am I wrong?
>> And if yes,what should I change to make it work?
>
> I'm no D expert, but here's what I got.
>
> 1. One problem is returning the wrong type from doIndex. When
> the condition "if(index.length == 1)" is false, the subsequent
> line is still compiled but fails to return a "ref T" since
> "array[index[0]]" is an array of T, not a T.
>
> The correct way (and better for performance, too) would be a
> compile-time "static if" there, like in the code below. (I
> don't quite get the syntax of the template constraint for
> doIndex, so I've just commented that out for now.)
>
> 2. The next problem is that fixed-size arrays obey value
> semantics, so they should be passed by reference and not by
> value.
>
> Here's what works for me (DMD 2.062):
>
> -----
> import std.stdio;
>
> template NDimensionalArrayType(T,alias size)
> if(is(typeof(size) _ : const int[]) && size.length > 0)
> {
> static if(size.length > 1)
> alias NDimensionalArrayType!(T,size[1..$])[size[0]]
> NDimensionalArrayType;
> else
> alias T[size[0]] NDimensionalArrayType;
> }
>
> struct NDimensionalArray(T,alias size)
> {
> private NDimensionalArrayType!(T,size) m_array;
> static ref T doIndex(Array)(ref Array array,const int[] index)
> //HERE
> // if(is(Array _ : NDimensionalArrayType!(T,s),const int[] s))
> {
> // assert(index.length == s.length);
> assert(index.length <= size.length);
> debug {writefln("doIndex (%s, %s = %s)",
> typeof(array).stringof,
> typeof(index).stringof,
> index);}
> static if(is(Array : T[]))
> {
> assert(index.length == 1);
> return array[index[0]];
> }
> else
> {
> assert(index.length > 1);
> return doIndex(array[index[0]],index[1..$]);
> }
> }
> ref T opIndex(const int[] index)
> {
> return doIndex(m_array,index);
> }
> alias m_array this;
> }
>
> void main()
> {
> NDimensionalArray!(int,[5,2]) array;
> array[[4,1]] = 1;
> assert(array[[4,1]] == 1);
> }
> -----
>
> With the debug mode on, it successfully prints the following:
>
> -----
> doIndex (int[2u][5u], const(int[]) = [4, 1])
> doIndex (int[2u], const(int[]) = [1])
> doIndex (int[2u][5u], const(int[]) = [4, 1])
> doIndex (int[2u], const(int[]) = [1])
> -----
>
> On a side note, this still looks like too much effort to do one
> opIndex in terms of performance. I doubt that any current
> compiler would optimize all that into a simple multiply +
> bounds-check + add loop.
>
> -----
> Ivan Kazmenko.
Thank you very much for your time)
Your answer is very useful.
More information about the Digitalmars-d-learn
mailing list