2 votes

Gérer les typedefs incohérents dans le code générique

Je rencontre régulièrement du code dans de grandes bases de données qui ne suivent pas la convention standard pour les typedefs, par ex. ThisType au lieu de this_type .

L'écriture de code générique où je ne peux plus compter sur this_type signifie que je dois fournir un code d'échafaudage pour chaque type qui n'a pas de this_type .

Je suppose que les deux this_type y ThisType peuvent être définis. Cependant, dans une grande base de code, cela ajoute du bruit supplémentaire et c'est quelque chose que les revues devront vérifier régulièrement.

Y a-t-il un moyen de l'envelopper dans une type_trait de sorte que je puisse écrire quelque chose du genre : this_type<SomeType>::value_type OU une autre solution générique ?

4voto

max66 Points 4276

Peut-être que cela peut être fait d'une manière plus simple... Quoi qu'il en soit, je propose une solution de répartition des balises / SFINAE.

Tout d'abord, un simple récursif tag struct

template <std::size_t N>
struct tag : public tag<N-1u>
{ };

template <>
struct tag<0u>
{ };

pour éviter les ambiguïtés dans les cas où plus d'un des noms de type possibles sont définis.

Ensuite, une fonction modèle (seulement déclarée) pour chaque type que vous voulez extraire des types possibles ; une pour type

template <typename T, std::void_t<typename T::type>* = nullptr>
typename T::type getType (tag<0u>);

un pour this_type

template <typename T, std::void_t<typename T::this_type>* = nullptr>
typename T::this_type getType (tag<1u>);

un pour ThisType

template <typename T, std::void_t<typename T::ThisType>* = nullptr>
typename T::ThisType getType (tag<2u>);

et un (pour être un peu idiot) pour MySillyTypeName

template <typename T, std::void_t<typename T::MySillyTypeName>* = nullptr>
typename T::MySillyTypeName getType (tag<3u>);

Observez que le nombre de tag sont différents : cela évite les ambiguïtés possibles et donne un ordre de priorité pour les noms.

Maintenant, une structure triviale qui utilise getType() pour extraire le type requis

template <typename T, typename U = decltype(getType<T>(tag<100u>()))>
struct GetType { using type = U; };

Voici un exemple de compilation complète de C++17

#include <type_traits>

template <std::size_t N>
struct tag : public tag<N-1u>
{ };

template <>
struct tag<0u>
{ };

template <typename T, std::void_t<typename T::type>* = nullptr>
typename T::type getType (tag<0u>);

template <typename T, std::void_t<typename T::this_type>* = nullptr>
typename T::this_type getType (tag<1u>);

template <typename T, std::void_t<typename T::ThisType>* = nullptr>
typename T::ThisType getType (tag<2u>);

template <typename T, std::void_t<typename T::MySillyTypeName>* = nullptr>
typename T::MySillyTypeName getType (tag<3u>);

template <typename T, typename U = decltype(getType<T>(tag<100u>()))>
struct GetType { using type = U; };

struct foo1 { using type = short; };
struct foo2 { using this_type = int; };
struct foo3 { using ThisType = long; };
struct foo4 { using MySillyTypeName = long long; };

int main()
{
  static_assert( std::is_same_v<short,     GetType<foo1>::type> );
  static_assert( std::is_same_v<int,       GetType<foo2>::type> );
  static_assert( std::is_same_v<long,      GetType<foo3>::type> );
  static_assert( std::is_same_v<long long, GetType<foo4>::type> );
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X