c++ templates metaprogramming

c++ - ¿Quieres un tipo de caja de interruptor constexpr en el tipo



templates metaprogramming (3)

Creo que sería más fácil usar la especialización de plantillas.

Código de ejemplo:

#include <iostream> struct A{}; struct B{}; struct C{}; struct D{}; template<typename T> constexpr const char* GetNameOfList(); //here you may want to make it return nullptr by default template<>constexpr const char* GetNameOfList<A>(){return "A";} template<>constexpr const char* GetNameOfList<B>(){return "B";} template<>constexpr const char* GetNameOfList<C>(){return "C";} int main(){ std::cout << GetNameOfList<A>() << ''/n''; std::cout << GetNameOfList<B>() << ''/n''; std::cout << GetNameOfList<C>() << ''/n''; //std::cout << GetNameOfList<D>() << ''/n''; //compile error here }

Actualmente estoy haciendo este truco para tener un cstring basado en un tipo:

template<class ListT> static char constexpr * GetNameOfList(void) { return std::conditional< std::is_same<ListT, LicencesList>::value, "licences", std::conditional< std::is_same<ListT, BundlesList>::value, "bundles", std::conditional< std::is_same<ListT, ProductsList>::value, "products", std::conditional< std::is_same<ListT, UsersList>::value, "users", nullptr > > > >; }

Pero este código no es muy atractivo, y si queremos verificar más tipos, esto podría ser ilegible. ¿Es una forma de hacer lo mismo como si hubiera un bloqueo de mayúsculas y minúsculas?

En realidad, el código es más complicado que eso, porque std :: conditional necesita algún tipo, así que necesitamos alguna clase para hacer el truco:

struct LicenceName { static char constexpr * value = "licences"; };

por ejemplo.


No es necesario recurrir a la metaprogramación, simplemente if s funciona bien:

template<class ListT> constexpr char const *GetNameOfList() { if(std::is_same<ListT, A>::value) return "A"; if(std::is_same<ListT, B>::value) return "B"; if(std::is_same<ListT, C>::value) return "C"; if(std::is_same<ListT, D>::value) return "D"; return nullptr; }

Véalo en vivo en Coliru


Podría crear un conjunto de cadenas constexpr más una tupla de tipos de lista para crear un list type -> index -> name mapeo list type -> index -> name (si necesita el index -> types containing strings mapeo index -> types containing strings solo usan tuple en lugar de un array). El enfoque de c ++ 17 podría verse como sigue:

#include <type_traits> #include <tuple> #include <utility> #include <iostream> struct LicencesList{}; struct BundlesList{}; struct ProductsList{}; struct UsersList{}; using ListTypes = std::tuple<LicencesList, BundlesList, ProductsList, UsersList>; constexpr const char *NameList[] = {"licences", "bundles", "products", "users"}; template <class Tup, class, class = std::make_index_sequence<std::tuple_size<Tup>::value>> struct index_of; template <class Tup, class T, std::size_t... Is> struct index_of<Tup, T, std::index_sequence<Is...>> { static constexpr std::size_t value = ((std::is_same<std::tuple_element_t<Is, Tup>, T>::value * Is) + ...); }; template<class ListT> static const char constexpr * GetNameOfList(void) { return NameList[index_of<ListTypes, ListT>::value]; } int main() { constexpr const char *value = GetNameOfList<BundlesList>(); std::cout << value << std::endl; }

[demo en vivo]

Si desea mantener la compatibilidad con c ++ 11, el enfoque sería un poco más largo (aquí utilicé la respuesta de Casey para implementar index_of estructura):

#include <type_traits> #include <tuple> #include <iostream> struct LicencesList{}; struct BundlesList{}; struct ProductsList{}; struct UsersList{}; using ListTypes = std::tuple<LicencesList, BundlesList, ProductsList, UsersList>; constexpr const char *NameList[] = {"licences", "bundles", "products", "users"}; template <class Tuple, class T> struct index_of; template <class T, class... Types> struct index_of<std::tuple<T, Types...>, T> { static const std::size_t value = 0; }; template <class T, class U, class... Types> struct index_of<std::tuple<U, Types...>, T> { static const std::size_t value = 1 + index_of<std::tuple<Types...>, T>::value; }; template<class ListT> static const char constexpr * GetNameOfList(void) { return NameList[index_of<ListTypes, ListT>::value]; } int main() { constexpr const char *value = GetNameOfList<BundlesList>(); std::cout << value << std::endl; }

[demo en vivo]