digitalmars.D.learn - Casting from an enum type to another enum type
- Roland Hadinger (28/28) Jun 24 2015 Hi!
- Meta (18/47) Jun 24 2015 std.conv.to really should be able to do this, but I guess not
- Meta (3/3) Jun 24 2015 Note that this is a very simple example. You need to check in the
- Roland Hadinger (9/19) Jun 24 2015 Thanks, that works!
Hi! What is the straightest way to safely cast from one enum type A to another enum type B, when B, in terms of values as well as identifiers, is a strict subset of A? Ideally, that should be as simple as "to!B(a)". So far I've tried a couple of things, and one way I found was to first cast A to int, then cast that to B, but that is not really straightforward. Example: import std.stdio; import std.conv; enum Color { r, o, y, g, b, i, v } enum StyleColor : int { o = Color.o, b = Color.b } void main() { auto c = Color.g; // Problem: the result is not guaranteed to be a StyleColor. // Does not throw, needs extra checks. auto d1 = cast(StyleColor) c; // Typesafe, but is not exactly straightforward. auto d2 = to!StyleColor(cast(int) c); // Error: template std.conv.toImpl cannot deduce // function from argument types !(StyleColor)(Color) // // Changing "enum StyleColor : Color" to "enum StyleColor : int" // in the definition above does not help either. auto d3 = to!StyleColor(c); }
Jun 24 2015
On Wednesday, 24 June 2015 at 15:29:03 UTC, Roland Hadinger wrote:Hi! What is the straightest way to safely cast from one enum type A to another enum type B, when B, in terms of values as well as identifiers, is a strict subset of A? Ideally, that should be as simple as "to!B(a)". So far I've tried a couple of things, and one way I found was to first cast A to int, then cast that to B, but that is not really straightforward. Example: import std.stdio; import std.conv; enum Color { r, o, y, g, b, i, v } enum StyleColor : int { o = Color.o, b = Color.b } void main() { auto c = Color.g; // Problem: the result is not guaranteed to be a StyleColor. // Does not throw, needs extra checks. auto d1 = cast(StyleColor) c; // Typesafe, but is not exactly straightforward. auto d2 = to!StyleColor(cast(int) c); // Error: template std.conv.toImpl cannot deduce // function from argument types !(StyleColor)(Color) // // Changing "enum StyleColor : Color" to "enum StyleColor : int" // in the definition above does not help either. auto d3 = to!StyleColor(c); }std.conv.to really should be able to do this, but I guess not many people have needed to do this. You can write an "extension" to `to` which does it for you: import std.traits; auto to(To, From)(From f) if (is(From == enum) && is(To == enum) && is(OriginalType!From : OriginalType!To)) { return cast(To)f; } enum Color { r, o, y, g, b, i, v } enum StyleColor : int { o = Color.o, b = Color.b } void main() { auto c = Color.g; auto s = c.to!StyleColor; }
Jun 24 2015
Note that this is a very simple example. You need to check in the function that a valid StyleColor will actually be produced. Otherwise, it'll happily produce a StyleColor that's invalid.
Jun 24 2015
On Wednesday, 24 June 2015 at 18:16:42 UTC, Meta wrote:std.conv.to really should be able to do this, but I guess not many people have needed to do this. You can write an "extension" to `to` which does it for you: import std.traits; auto to(To, From)(From f) if (is(From == enum) && is(To == enum) && is(OriginalType!From : OriginalType!To)) { return cast(To)f; }Thanks, that works! I'll add this to my project's 'helpers' module, with the "return" line replaced by: foreach (m; EnumMembers!To) { if (m == f) return m; } throw new ConvException("Value not in enum");
Jun 24 2015