question with compile-time reflection

Ivan Kazmenko gassa at mail.ru
Sat Mar 9 15:05:55 PST 2013


> 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.


More information about the Digitalmars-d-learn mailing list