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;
}

Reply via email to