c++ - Deducción de argumento de plantilla con enumeraciones fuertemente tipadas.
templates c++17 (4)
Esta pregunta tiene una respuesta aceptada (upvoted).
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 del 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>;
Si tengo una enumeración normal (débil), puedo usar sus valores enumerados como parámetros de plantilla no tipo, como por ejemplo:
enum { Cat, Dog, Horse };
template <int Val, typename T> bool magic(T &t)
{
return magical_traits<Val>::invoke(t);
}
y llámalo 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 manera de evitar escribir tanto la clase enum como el valor, a menos que
#define MAGIC(E, T) (magic<decltype(E), E>(T));
Lo siento tengo que decirte eso
No es posible
Tome la macro, colóquela en un encabezado temible y protéjala del script de limpieza de su colega. Esperar lo mejor.
Puedes hacerlo de esta manera, si puedes 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
Si solo está interesado en el valor de la enum
, y no en su tipo, debería poder usar una función constexpr
para convertir el valor en un 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 lo señalaron otros, si quiere que esto también dependa del tipo, no funcionará.