Thread overview
Base type for arrays
Jun 17, 2015
jmh530
Jun 17, 2015
Alex Parrill
Jun 17, 2015
jmh530
Jun 17, 2015
Alex Parrill
Jun 17, 2015
Namespace
Jun 17, 2015
jmh530
Jun 17, 2015
Namespace
Jun 18, 2015
Meta
June 17, 2015
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]
}
June 17, 2015
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.
June 17, 2015
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.
June 17, 2015
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'

June 17, 2015
----
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
June 17, 2015
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.
June 17, 2015
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
June 18, 2015
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));
}