www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Constructing an enum using the members of an AliasSeq as enumerator

reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
What's the easiest way to create an `enum` using the symbol names 
of an `AliasSeq` as enumerator names?

That is, given

     alias Types = AliasSeq!(byte, short, int);

we need some compile-time type-constructor `makeEnum` called as

     alias E = makeEnum!Types;

that should be equivalent to

     enum E { _byte, _short, _int }

I guess a `mixin` is the way to go here, right?
Apr 27 2016
parent reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Wednesday, 27 April 2016 at 10:49:54 UTC, Nordlöw wrote:
 What's the easiest way to create an `enum` using the symbol 
 names of an `AliasSeq` as enumerator names?
/** Returns: a `string` containing the definition of an `enum` named `name` and with enumerator names given by `Es`, optionally prepended with `prefix` and appended with `suffix`. TODO Move to Phobos std.typecons */ string makeEnumDefinitionString(string name, string prefix = `_`, string suffix = ``, Es...)() if (Es.length >= 1) { typeof(return) s = `enum ` ~ name ~ ` { `; foreach (E; Es) { s ~= prefix ~ E.stringof ~ suffix ~ `, `; } s ~= `}`; return s; } safe pure nothrow nogc unittest { import std.meta : AliasSeq; alias Types = AliasSeq!(byte, short); mixin(makeEnumDefinitionString!("Type", `_`, `_`, Types)); static assert(is(Type == enum)); static assert(Type._byte_.stringof == "_byte_"); static assert(Type._short_.stringof == "_short_"); } Can it be made more elegant? Destroy!
Apr 27 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 27.04.2016 13:06, Nordlöw wrote:
 /** Returns: a `string` containing the definition of an `enum` named
 `name` and
      with enumerator names given by `Es`, optionally prepended with
 `prefix` and
      appended with `suffix`.

      TODO Move to Phobos std.typecons
 */
 string makeEnumDefinitionString(string name,
                                  string prefix = `_`,
                                  string suffix = ``,
                                  Es...)()
      if (Es.length >= 1)
 {
      typeof(return) s = `enum ` ~ name ~ ` { `;
      foreach (E; Es)
      {
          s ~= prefix ~ E.stringof ~ suffix ~ `, `;
      }
      s ~= `}`;
      return s;
 }

  safe pure nothrow  nogc unittest
 {
      import std.meta : AliasSeq;
      alias Types = AliasSeq!(byte, short);
      mixin(makeEnumDefinitionString!("Type", `_`, `_`, Types));
      static assert(is(Type == enum));
      static assert(Type._byte_.stringof == "_byte_");
      static assert(Type._short_.stringof == "_short_");
 }

 Can it be made more elegant?
I'd hide the string mixin in the template: ---- template makeEnumFromSymbolNames(string prefix = `_`, string suffix = ``, Es...) if (Es.length >= 1) { enum members = { string s = ""; foreach (E; Es) { s ~= prefix ~ E.stringof ~ suffix ~ `, `; } return s; }(); mixin("enum makeEnumFromSymbolNames {" ~ members ~ "}"); } safe pure nothrow nogc unittest { import std.meta : AliasSeq; alias Types = AliasSeq!(byte, short); alias Type = makeEnumFromSymbolNames!(`_`, `_`, Types); static assert(is(Type == enum)); static assert(Type._byte_.stringof == "_byte_"); static assert(Type._short_.stringof == "_short_"); } ---- The `foreach` could be replaced with `map` and `joiner`, but I'm not sure if that would be an improvement. `format` might be interesting: ---- import std.format; import std.meta: staticMap; enum stringOf(t...) = t[0].stringof; mixin(format( "enum makeEnumFromSymbolNames {%-(" ~ prefix ~ "%s" ~ suffix ~"%|, %)}", [staticMap!(stringOf, Es)] )); ---- That takes longer to compile, though. Probably needs more memory as well.
Apr 27 2016
parent =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Wednesday, 27 April 2016 at 15:30:55 UTC, ag0aep6g wrote:
 That takes longer to compile, though. Probably needs more 
 memory as well.
Thanks! Added here https://github.com/nordlow/phobos-next/blob/master/src/typecons_ex.d#L425
Apr 28 2016