Pregunta

Si tengo una enumeración normal (débil), puedo usar sus valores enumerados como parámetros de plantilla que no son de tipo, así:

enum { Cat, Dog, Horse };

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}

y llámelo como: magic<Cat>(t)

por lo que puedo ver, si tengo una enumeración fuertemente tipada y no quiero codificar el tipo de enumeración, termino con:

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal, typename T> bool magic(T &t)
{
    return magical_traits<EnumVal>::invoke(t);
}

y ahora tengo que escribir: magic<Animal, Animal::Cat>(t), que parece redundante.

¿Hay alguna forma de evitar escribir tanto la clase de enumeración como el valor, menos

#define MAGIC(E, T) (magic<decltype(E), E>(T));
¿Fue útil?

Solución

Puede hacerlo así, si puede usar C ++ 17

#include <type_traits>

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal> 
void magic_impl()
{
    static_assert(std::is_same_v<EnumClass, Animal>);
    static_assert(EnumVal == Animal::Cat);
}

template <auto EnumVal>
void magic()
{
    magic_impl<decltype(EnumVal), EnumVal>();
}

int main()
{
    magic<Animal::Cat>();
}

demostración: http://coliru.stacked-crooked.com/a/9ac5095e8434c9da

Otros consejos

Lo siento, tengo que decirte que

No es posible

Tome la macro, colóquela en un encabezado con nombre aterrador y protéjala del script de limpieza de su colega.Esperar lo mejor.

Si solo está interesado en el valor de enum, y no en su tipo, debería poder usar una función constexpr para convertir el valor en un número entero, evitando repetir el nombre del tipo.

enum class Animal { Cat, Dog, Horse };

template <typename T> constexpr int val(T t)
{
    return static_cast<int>(t);
}

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}

magic<val(Animal::Cat)>(t);

Sin embargo, como ya han señalado otros, si desea que esto también dependa del tipo, no funcionará.

Esta pregunta tiene una respuesta aceptada (votada a favor).

Mientras refactorizaba mi propio código, descubrí una solución más completa:

Paso 1: usando el código que estaba escribiendo:

template<typename V, typename EnumClass, EnumClass Discriminator>
class strong_type final // type-safe wrapper for input parameters
{
    V value;
public:
    constexpr explicit strong_type(V x): value{x} {}
    constexpr auto get() const { return value; }
};

Paso 2: código de cliente:

enum class color { red, green, blue, alpha };

// the part OP was asking about:
template<color C>
using color_channel = strong_type<std::uint8_t, color, C>;

using red = color_channel<color::red>; // single argument here
using green = color_channel<color::green>;
using blue = color_channel<color::blue>;
using alpha = color_channel<color::alpha>;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top