www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Base type for arrays

reply "jmh530" <john.michael.hall gmail.com> writes:
I want to write a function template that works for any array of a 
particular type, but not the base type, so real[], real[][], etc, 
but not real. I was using ForeachType to do some testing, but it 
doesn't really get the base type. It just takes one of the [] off 
and returns the remaining type (see code below). ElementType from 
std.range seems to operate in a similar way. There are also ways 
to do this for associative arrays, but they don't apply here 
either.

How do I go about just getting the actual base type of an array?

import std.stdio;
import std.traits;

void main() {
	real[2] x;
	x[0] = 0;
	x[1] = 1;
	
	writeln(is(ForeachType!(typeof(x)) == real)); //prints true

	real[2][2] xx;
	xx[0][0] = 0;
	xx[1][0] = 1;
	xx[0][1] = 2;
	xx[1][1] = 3;
	
	writeln(is(ForeachType!(typeof(xx)) == real));  //prints false
	writeln(typeid(ForeachType!(typeof(xx)));       //prints real[2]
}
Jun 17 2015
next sibling parent reply "Alex Parrill" <initrd.gz gmail.com> writes:
On Wednesday, 17 June 2015 at 19:53:07 UTC, jmh530 wrote:
 I want to write a function template that works for any array of 
 a particular type, but not the base type, so real[], real[][], 
 etc, but not real. I was using ForeachType to do some testing, 
 but it doesn't really get the base type. It just takes one of 
 the [] off and returns the remaining type (see code below). 
 ElementType from std.range seems to operate in a similar way. 
 There are also ways to do this for associative arrays, but they 
 don't apply here either.

 How do I go about just getting the actual base type of an array?

 import std.stdio;
 import std.traits;

 void main() {
 	real[2] x;
 	x[0] = 0;
 	x[1] = 1;
 	
 	writeln(is(ForeachType!(typeof(x)) == real)); //prints true

 	real[2][2] xx;
 	xx[0][0] = 0;
 	xx[1][0] = 1;
 	xx[0][1] = 2;
 	xx[1][1] = 3;
 	
 	writeln(is(ForeachType!(typeof(xx)) == real));  //prints false
 	writeln(typeid(ForeachType!(typeof(xx)));       //prints 
 real[2]
 }
Try: void foo(T)(T[] arg) { // In here, T should be the element type, and T[] the array type. } Not a general solution, but you mentioned that you wanted this for a function parameter.
Jun 17 2015
parent reply "jmh530" <john.michael.hall gmail.com> writes:
On Wednesday, 17 June 2015 at 20:06:54 UTC, Alex Parrill wrote:

 Try:

 void foo(T)(T[] arg) {
     // In here, T should be the element type, and T[] the array 
 type.
 }

 Not a general solution, but you mentioned that you wanted this 
 for a function parameter.
I don't think this works for multi-dimensional arrays. I tried void foo(T)(T[] arg) if (isArray!(T[]) && is(T == real)) { writeln("foo has run for ", arg); } and it only worked on the one-dimensional one.
Jun 17 2015
next sibling parent "Alex Parrill" <initrd.gz gmail.com> writes:
On Wednesday, 17 June 2015 at 20:20:29 UTC, jmh530 wrote:
 On Wednesday, 17 June 2015 at 20:06:54 UTC, Alex Parrill wrote:

 Try:

 void foo(T)(T[] arg) {
     // In here, T should be the element type, and T[] the 
 array type.
 }

 Not a general solution, but you mentioned that you wanted this 
 for a function parameter.
I don't think this works for multi-dimensional arrays. I tried void foo(T)(T[] arg) if (isArray!(T[]) && is(T == real)) { writeln("foo has run for ", arg); } and it only worked on the one-dimensional one.
Yea, it doesn't, it only goes one-level deep. I misunderstood. Here's a recursive template: template ArrayBaseType(T) { static if(is(T : U[], U)) alias ArrayBaseType = ArrayBaseType!U; else alias ArrayBaseType = T; } pragma(msg, ArrayBaseType!(int[][][])); // prints 'int'
Jun 17 2015
prev sibling parent reply "Namespace" <rswhite4 gmail.com> writes:
----
import std.stdio;

template BaseTypeOf(T) {
     static if (is(T : U[], U))
         alias BaseTypeOf = BaseTypeOf!(U);
     else
         alias BaseTypeOf = T;
}

void foo(T : U[], U)(T arr) if (is(BaseTypeOf!(U) == real)) {
	
}

void main() {
	//real _x;
	real[2] x;
	real[2][2] xx;
	real[2][2][2] xxx;
	
	//float[2] yy;
	
	//foo(_x);
	foo(x);
	foo(xx);
	foo(xxx);
	
	//foo(yy);
}
----

should work
Jun 17 2015
parent reply "jmh530" <john.michael.hall gmail.com> writes:
On Wednesday, 17 June 2015 at 20:33:11 UTC, Namespace wrote:
 ----
 import std.stdio;

 template BaseTypeOf(T) {
     static if (is(T : U[], U))
         alias BaseTypeOf = BaseTypeOf!(U);
     else
         alias BaseTypeOf = T;
 }

 void foo(T : U[], U)(T arr) if (is(BaseTypeOf!(U) == real)) {
 	
 }

 void main() {
 	//real _x;
 	real[2] x;
 	real[2][2] xx;
 	real[2][2][2] xxx;
 	
 	//float[2] yy;
 	
 	//foo(_x);
 	foo(x);
 	foo(xx);
 	foo(xxx);
 	
 	//foo(yy);
 }
 ----

 should work
Thanks. I'm going to make a lot of use of this. I would say it deserves to be in std.traits.
Jun 17 2015
parent "Namespace" <rswhite4 gmail.com> writes:
On Wednesday, 17 June 2015 at 20:58:10 UTC, jmh530 wrote:
 On Wednesday, 17 June 2015 at 20:33:11 UTC, Namespace wrote:
 ----
 import std.stdio;

 template BaseTypeOf(T) {
     static if (is(T : U[], U))
         alias BaseTypeOf = BaseTypeOf!(U);
     else
         alias BaseTypeOf = T;
 }

 void foo(T : U[], U)(T arr) if (is(BaseTypeOf!(U) == real)) {
 	
 }

 void main() {
 	//real _x;
 	real[2] x;
 	real[2][2] xx;
 	real[2][2][2] xxx;
 	
 	//float[2] yy;
 	
 	//foo(_x);
 	foo(x);
 	foo(xx);
 	foo(xxx);
 	
 	//foo(yy);
 }
 ----

 should work
Thanks. I'm going to make a lot of use of this. I would say it deserves to be in std.traits.
Maybe you can also make use of some of those here (just in case): https://github.com/Dgame/m3/blob/master/source/m3/m3.d
Jun 17 2015
prev sibling parent "Meta" <jared771 gmail.com> writes:
On Wednesday, 17 June 2015 at 19:53:07 UTC, jmh530 wrote:
 I want to write a function template that works for any array of 
 a particular type, but not the base type, so real[], real[][], 
 etc, but not real. I was using ForeachType to do some testing, 
 but it doesn't really get the base type. It just takes one of 
 the [] off and returns the remaining type (see code below). 
 ElementType from std.range seems to operate in a similar way. 
 There are also ways to do this for associative arrays, but they 
 don't apply here either.

 How do I go about just getting the actual base type of an array?

 import std.stdio;
 import std.traits;

 void main() {
 	real[2] x;
 	x[0] = 0;
 	x[1] = 1;
 	
 	writeln(is(ForeachType!(typeof(x)) == real)); //prints true

 	real[2][2] xx;
 	xx[0][0] = 0;
 	xx[1][0] = 1;
 	xx[0][1] = 2;
 	xx[1][1] = 3;
 	
 	writeln(is(ForeachType!(typeof(xx)) == real));  //prints false
 	writeln(typeid(ForeachType!(typeof(xx)));       //prints 
 real[2]
 }
Here is another solution which is more general in that it can be used with any input range. import std.range: isInputRange; import std.array; template FlattenedType(R, int depth = int.max) if (isInputRange!R && depth >= 0) { static if (depth == 0) { alias FlattenedType = R; } else { alias FrontType = typeof(R.init.front); static if (isInputRange!FrontType) { alias FlattenedType = FlattenedType!(FrontType, depth - 1); } else { alias FlattenedType = R; } } } alias ArrayBaseType(T: U[], U) = typeof(FlattenedType!T.init.front); void main() { assert(is(FlattenedType!(int[][][]) == int[])); assert(is(ArrayBaseType!(int[][][]) == int)); }
Jun 17 2015