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