2017-08-15 3 views
1

Est-il possible d'écrire une métafonction qui, étant donné un type avec plusieurs occurrences de certain type template<class> class Decor, renvoie le type sans les apparences de la classe Decorator.Supprimer tous les types de wrapper dans un type imbriqué

Un exemple serait de convertir le type suivant A<Decor<T<B<A<Decor<C>>>>>> dans A<T<B<A<C>>>>

Nous partons du principe que la structure du dernier type est en effet un type correct, mais nous ne présumez pas quoi que ce soit sur la structure du type d'entrée . Il se peut que certains types utilisés pour construire le type d'entrée aient la forme template<class...> class ou toute autre classe de type.

Répondre

0
template <class T> 
struct RemDec 
{ using type = T; }; 
template <class T> 
struct RemDec<Decor<T>> 
{ using type = T; }; 
template <class T> 
struct RemDec<T&> 
{ using type = typename RemDec<T>::type&; }; 
template <class T> 
struct RemDec<T&&> 
{ using type = typename RemDec<T>::type&&; }; 
template <class T> 
struct RemDec<const T> 
{ using type = typename RemDec<T>::type const; }; 
template <class T> 
struct RemDec<volatile T> 
{ using type = typename RemDec<T>::type volatile; }; 
template <template <typename...> class TT, class... Ts> 
struct RemDec<TT<Ts...>> 
{ using type = TT<typename RemDec<Ts>::type...>; } 

Vous aurez besoin d'encore plus de spécialisations si vos modèles peuvent avoir des arguments value- ou template-template.

+0

Vous avez un très bon point, en effet. – Lezkus

1

Vous pouvez utiliser un modèle de classe et deux spécialisations comme celles-ci:

template<typename T> 
struct RemDec { 
    using type = T; 
}; 

template<template<typename...> class C, typename... T> 
struct RemDec<C<T...>> { 
    using type = C<typename RemDec<T>::type...>; 
}; 

template<typename T> 
struct RemDec<Decorator<T>> { 
    using type = typename RemDec<T>::type; 
}; 

Le modèle de classe aide à itérer arrêter sur votre chaîne de types.
La première spécialisation mémorise un modèle de classe et aide à nettoyer ce qui reste.
La dernière spécialisation supprime le Decorator détecté et continue d'analyser ce qui reste.


Il suit un minimum, par exemple de travail:

#include<type_traits> 

template<typename> 
struct Decorator {}; 

template<typename...> 
struct S {}; 

template<typename T> 
struct RemDec { 
    using type = T; 
}; 

template<template<typename...> class C, typename... T> 
struct RemDec<C<T...>> { 
    using type = C<typename RemDec<T>::type...>; 
}; 

template<typename T> 
struct RemDec<Decorator<T>> { 
    using type = typename RemDec<T>::type; 
}; 

int main() { 
    static_assert(std::is_same< 
     typename RemDec<S<Decorator<S<S<Decorator<S<int>>>>>, Decorator<S<double>>>>::type, 
     S<S<S<S<int>>>, S<double>> 
    >::value, "!"); 
} 

Comme vous pouvez le voir en l'exécutant, tout exemple de Decorator est retiré du type d'original.

+0

Dieu, vous avez raison. J'ai mis en place presque cela, mais j'ai raté quelque chose et je pensais que vous ne pouviez pas faire ce type de correspondance. Comme je l'ai souligné, la classe pourrait être variée dans son argument de modèle, mais la généralisation est triviale. Merci beaucoup! – Lezkus

+0

@Lezkus Vous avez manqué le commentaire variadique. Donnez-moi quelques minutes pour intégrer la réponse à cela. – skypjack

+1

@Lezkus Terminé. Maintenant, le code est _variadic-oriented_. ;-) – skypjack