déduction d'argument du modèle avec des énumérations fortement typées
-
29-10-2019 - |
Question
Si j'ai une énumération normale (faible), je peux utiliser ses valeurs énumérées comme paramètres de modèle non de type, comme ainsi:
enum { Cat, Dog, Horse };
template <int Val, typename T> bool magic(T &t)
{
return magical_traits<Val>::invoke(t);
}
Et appelez-le comme: magic<Cat>(t)
Pour autant que je puisse voir, si j'ai une énumération fortement typée et que je ne veux pas coder dur le type d'énumération, je me retrouve avec:
enum class Animal { Cat, Dog, Horse };
template <typename EnumClass, EnumClass EnumVal, typename T> bool magic(T &t)
{
return magical_traits<EnumVal>::invoke(t);
}
Et maintenant je dois écrire: magic<Animal, Animal::Cat>(t)
, ce qui semble redondant.
Existe-t-il un moyen d'éviter de taper à la fois la classe d'énumération et la valeur, à court
#define MAGIC(E, T) (magic<decltype(E), E>(T));
La solution
Vous pouvez le faire comme ça, si vous pouvez utiliser 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>();
}
Autres conseils
Je suis désolé, je dois te dire ça
Ce n'est pas possible
Prenez la macro, mettez-la dans une en-tête effrayante nommée et protégez-la du script de nettoyage de votre collègue. Espérons le meilleur.
Si vous êtes seulement intéressé par le enum
Valeur, et non son type, vous devriez pouvoir utiliser un constexpr
Fonction pour convertir la valeur en un entier, en évitant de répéter le nom de type.
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);
Cependant, comme le souligne déjà les autres, si vous voulez que cela dépend également du type, cela ne fonctionnera pas.
Cette question a un réponse acceptée (upvote).
En refactorisant mon propre code, j'ai trouvé une solution plus complète:
Étape 1: en utilisant le code que j'écrivais:
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; }
};
Étape 2: Code client:
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>;