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