www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to enumerate a sequence?

reply Victor Porton <porton narod.ru> writes:
.enumerate does not work for compile-time sequences. Consider for 
the sake of discussion the following nonsense (I know it cannot 
be done without enumerate) code:

import std.meta;
import std.range;

string join(Fields...)() {
   enum f(size_t i) = __traits(identifier, Fields[i]);
   return staticMap!f(Fields.enumerate).join('\n'); // does not 
compile because of .enumerate
}

void main(string[] args)
{
     string r = join!(int, float)();
}

How to make it compile?
Feb 27 2019
next sibling parent Victor Porton <porton narod.ru> writes:
On Wednesday, 27 February 2019 at 13:15:06 UTC, Victor Porton 
wrote:
 .enumerate does not work for compile-time sequences. Consider 
 for the sake of discussion the following nonsense (I know it 
 cannot be done without enumerate) code:
I want namely integer (or size_t) index!
Feb 27 2019
prev sibling parent Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Wednesday, 27 February 2019 at 13:15:06 UTC, Victor Porton 
wrote:
 .enumerate does not work for compile-time sequences. Consider 
 for the sake of discussion the following nonsense (I know it 
 cannot be done without enumerate) code:

 import std.meta;
 import std.range;

 string join(Fields...)() {
   enum f(size_t i) = __traits(identifier, Fields[i]);
   return staticMap!f(Fields.enumerate).join('\n'); // does not 
 compile because of .enumerate
 }

 void main(string[] args)
 {
     string r = join!(int, float)();
 }

 How to make it compile?
Sadly, we cannot treat all compile-time values the same way we do run-time values. In this case, that's evident with Fields being an AliasSeq, not an array or other range. Since enumerate and join operate on ranges, they get confused when you give them an AliasSeq. You also are probably not giving enough information about what you're actually trying to do. First, __traits(identifier, Fields[0]) simply fails to compile with the given arguments, since int doesn't have an identifier. Second, it's very unclear why you need an int index, since you're not using it in a way you couldn't easier do without. Here's how I would implement your join function wihout any further knowledge of these questions: // Moved outside join due to the thrice-damned issue 5710 enum getIdentifier(T...) = __traits(identifier, T[0]); string join(Fields...)() { import std.range : join; import std.meta : staticMap; alias names = staticMap!(getIdentifier, Fields); return [names].join('\n'); } However, since you seem adamant you need the index as an int or size_t: string join(Fields...)() { import std.range : join, iota; import std.meta : staticMap, aliasSeqOf; enum getIdentifier(size_t i) = __traits(identifier, Fields[i]); alias numbers = aliasSeqOf!(Fields.length.iota); return [staticMap!(getIdentifier, numbers)].join('\n'); } Also, fixed the calling code so it has actual identifiers: void main(string[] args) { int i; float f; string r = join!(i, f)(); } -- Simen
Feb 27 2019