www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to get the element type of an array?

reply Jon Degenhardt <jond noreply.com> writes:
What's the best way to get the element type of an array at 
compile time?

Something like std.range.ElementType except that works on any 
array type. There is std.traits.ForeachType, but it wasn't clear 
if that was the right thing.

--Jon
Aug 24 2020
next sibling parent Harry Gillanders <contact harrygillanders.com> writes:
On Tuesday, 25 August 2020 at 03:41:06 UTC, Jon Degenhardt wrote:
 What's the best way to get the element type of an array at 
 compile time?

 Something like std.range.ElementType except that works on any 
 array type. There is std.traits.ForeachType, but it wasn't 
 clear if that was the right thing.

 --Jon
One way (maybe not the best way) is to use the type of the array's ptr property when dereferenced, e.g. import std.traits : isArray; template ArrayElementOf (Array) if (isArray!Array) { alias ArrayElementOf = typeof(*Array.init.ptr); }
Aug 24 2020
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Aug 25, 2020 at 03:41:06AM +0000, Jon Degenhardt via
Digitalmars-d-learn wrote:
 What's the best way to get the element type of an array at compile
 time?
 
 Something like std.range.ElementType except that works on any array
 type.  There is std.traits.ForeachType, but it wasn't clear if that
 was the right thing.
[...] alias T = ... /* the type to inspect */ static if (is(T : E[], E)) { ... /* in this block, E is the element type */ } Or if you need to use it in another expression: template ArrayElemType(T) { static if (is(T : E[], E)) { alias ArrayElemType = E; } else alias ArrayElemType = void; // or static assert(0) if it should be an error } int[] myArr; pragma(msg, ArrayElemType!(typeof(myArr))); // int string myStr; pragma(msg, ArrayElemType!(typeof(myStr))); // immutable(char) T -- The best way to destroy a cause is to defend it poorly.
Aug 24 2020
parent Jon Degenhardt <jond noreply.com> writes:
On Tuesday, 25 August 2020 at 04:36:56 UTC, H. S. Teoh wrote:
 [...]
Harry Gillanders, H.S. Teoh, Thank you both for the quick replies. Both methods address my needs. Very much appreciated, I was having trouble figuring this one out. --Jon
Aug 24 2020
prev sibling next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Tuesday, 25 August 2020 at 03:41:06 UTC, Jon Degenhardt wrote:
 What's the best way to get the element type of an array at 
 compile time?

 Something like std.range.ElementType except that works on any 
 array type. There is std.traits.ForeachType, but it wasn't 
 clear if that was the right thing.

 --Jon
I'm curious to know what are the array types that were not accepted by ElementType ( or ElementEncodingType ) ?
Aug 24 2020
parent reply Jon Degenhardt <jond noreply.com> writes:
On Tuesday, 25 August 2020 at 05:02:46 UTC, Basile B. wrote:
 On Tuesday, 25 August 2020 at 03:41:06 UTC, Jon Degenhardt 
 wrote:
 What's the best way to get the element type of an array at 
 compile time?

 Something like std.range.ElementType except that works on any 
 array type. There is std.traits.ForeachType, but it wasn't 
 clear if that was the right thing.

 --Jon
I'm curious to know what are the array types that were not accepted by ElementType ( or ElementEncodingType ) ?
Interesting. I need to test static arrays. In fact 'ElementType' does work with static arrays. Which is likely what you expected. I assumed ElementType would not work, because static arrays don't satisfy 'isInputRange', and the documentation for ElementType says:
 The element type is determined as the type yielded by r.front 
 for an object r of type R. [...] If R doesn't have front, 
 ElementType!R is void.
But, if std.range is imported, a static array does indeed get a 'front' member. It doesn't satisfy isInputRange, but it does have a 'front' element. The situation is still confusing though. If only 'std.range.ElementType' is imported, a static array does not have a 'front' member, but ElementType still gets the correct type. (This is where the documentation says it'll return void.) --- Import std.range --- safe unittest { import std.range; ubyte[10] staticArray; ubyte[] dynamicArray = new ubyte[](10); static assert(is(ElementType!(typeof(staticArray)) == ubyte)); static assert(is(ElementType!(typeof(dynamicArray)) == ubyte)); // front is available static assert(__traits(compiles, staticArray.front)); static assert(__traits(compiles, dynamicArray.front)); static assert(is(typeof(staticArray.front) == ubyte)); static assert(is(typeof(dynamicArray.front) == ubyte)); } --- Import std.range.ElementType --- safe unittest { import std.range : ElementType; ubyte[10] staticArray; ubyte[] dynamicArray = new ubyte[](10); static assert(is(ElementType!(typeof(staticArray)) == ubyte)); static assert(is(ElementType!(typeof(dynamicArray)) == ubyte)); // front is not available static assert(!__traits(compiles, staticArray.front)); static assert(!__traits(compiles, dynamicArray.front)); static assert(!is(typeof(staticArray.front) == ubyte)); static assert(!is(typeof(dynamicArray.front) == ubyte)); } This suggests the documentation for ElementType not quite correct.
Aug 25 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/25/20 4:38 AM, Jon Degenhardt wrote:
 On Tuesday, 25 August 2020 at 05:02:46 UTC, Basile B. wrote:
 On Tuesday, 25 August 2020 at 03:41:06 UTC, Jon Degenhardt wrote:
 What's the best way to get the element type of an array at compile time?

 Something like std.range.ElementType except that works on any array 
 type. There is std.traits.ForeachType, but it wasn't clear if that 
 was the right thing.

 --Jon
I'm curious to know what are the array types that were not accepted by ElementType ( or ElementEncodingType ) ?
Interesting. I need to test static arrays. In fact 'ElementType' does work with static arrays. Which is likely what you expected.
Also note that due to autodecoding, ElementType says `dchar` for strings. ElementEncodingType should be the choice if you are looking for the array element type. But you could also use the techniques specified here (and might be less confusing).
 But, if std.range is imported, a static array does indeed get a 'front' 
 member. It doesn't satisfy isInputRange, but it does have a 'front' 
 element.
Because you can't pop the front of a static array. front works because a static array automatically casts to a normal array (there is no specialized overload for static arrays).
 The situation is still confusing though. If only 'std.range.ElementType' 
 is imported, a static array does not have a 'front' member, but 
 ElementType still gets the correct type. (This is where the 
 documentation says it'll return void.)
You are maybe thinking of how C works? D imports are different, the code is defined the same no matter how it is imported. *your* module cannot see std.range.primitives.front, but the range module itself can see that UFCS function. This is also why ElementType will fail on types that have UFCS front defined, but not imported directly from std.range.primitives. -Steve
Aug 25 2020
parent Jon Degenhardt <jond noreply.com> writes:
On Tuesday, 25 August 2020 at 12:50:35 UTC, Steven Schveighoffer 
wrote:
 The situation is still confusing though. If only 
 'std.range.ElementType' is imported, a static array does not 
 have a 'front' member, but ElementType still gets the correct 
 type. (This is where the documentation says it'll return void.)
You are maybe thinking of how C works? D imports are different, the code is defined the same no matter how it is imported. *your* module cannot see std.range.primitives.front, but the range module itself can see that UFCS function.
This is a good characteristic. But the reason it surprised me was that I expected to be able to manually expand the ElementType (or ElementEncodingType) template see the results of the expressions it uses. template ElementType(R) { static if (is(typeof(R.init.front.init) T)) alias ElementType = T; else alias ElementType = void; } So, yes, I was expecting this to behave like an inline code expansion. Yesterday I was doing that for 'hasSlicing', which has a more complicated set of tests. I wanted to see exactly which expression in 'hasSlicing' was causing it to return false for a struct I wrote. (Turned out to be a test for 'length'.) I'll have to be more careful about this.
Aug 25 2020
prev sibling parent reply FreeSlave <freeslave93 gmail.com> writes:
On Tuesday, 25 August 2020 at 03:41:06 UTC, Jon Degenhardt wrote:
 What's the best way to get the element type of an array at 
 compile time?

 Something like std.range.ElementType except that works on any 
 array type. There is std.traits.ForeachType, but it wasn't 
 clear if that was the right thing.

 --Jon
Why not just use typeof(a[0]) It does not matter if array is empty or not. Typeof does not actually evaluate its expression, just the type.
Aug 25 2020
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Aug 25, 2020 at 03:02:14PM +0000, FreeSlave via Digitalmars-d-learn
wrote:
 On Tuesday, 25 August 2020 at 03:41:06 UTC, Jon Degenhardt wrote:
 What's the best way to get the element type of an array at compile
 time?
 
 Something like std.range.ElementType except that works on any array
 type. There is std.traits.ForeachType, but it wasn't clear if that
 was the right thing.
 
 --Jon
Why not just use typeof(a[0]) It does not matter if array is empty or not. Typeof does not actually evaluate its expression, just the type.
+1, why didn't I think of this before. :-D T -- Political correctness: socially-sanctioned hypocrisy.
Aug 25 2020
prev sibling parent Jon Degenhardt <jond noreply.com> writes:
On Tuesday, 25 August 2020 at 15:02:14 UTC, FreeSlave wrote:
 On Tuesday, 25 August 2020 at 03:41:06 UTC, Jon Degenhardt 
 wrote:
 What's the best way to get the element type of an array at 
 compile time?

 Something like std.range.ElementType except that works on any 
 array type. There is std.traits.ForeachType, but it wasn't 
 clear if that was the right thing.

 --Jon
Why not just use typeof(a[0]) It does not matter if array is empty or not. Typeof does not actually evaluate its expression, just the type.
Wow, yet another way that should have been obvious! Thanks! --Jon
Aug 25 2020