2017-10-11 4 views
3

Je suis en train d'écrire une méthode qui est en charge du formatage et de l'impression d'informations.Détection si un type de modèle est lui-même un type de modèle

Il existe un problème/une caractéristique dans boost::optional<T>, qui will print an extra blank space lors de la sortie dans un flux si et seulement si le optional a une valeur.

Je peux voir deux options:

  • Utilisation deux fonctions différentes: un général et qui traite explicitement boost::optional<T>
  • En utilisant une seule fonction qui permet de détecter si l'argument est de type boost::optional<T> et beaucoup avec en conséquence

Option 1 pourrait être quelque chose comme ceci:

template <typename T> 
void print(const T& o) 
{ 
    std::cout << o << "\n"; 
} 

template <typename T> 
void print_optional(const boost::optional<T>& o) 
{ 
    if (o) 
     print(*o); 
    else 
     print("--"); 
} 

Cela fonctionne, mais il a le problème qu'aucune erreur de compilation ne se produit si nous appelons print() avec boost::optional. Je sais de static_assert et std::is_type, mais puisque boost::optional est lui-même modèle je ne sais pas comment vérifier contre cela.

Option 2 serait idéal pour moi, mais la question reste: comment demander le code si une variable est un boost::optional<T> quel que soit T?

+0

La question posée: "vous ne pouvez pas". Un type est un type. Cependant, vous ne voulez pas cela, vous voulez surcharger les spécialisations (partielles). – sehe

Répondre

3

Comme d'autres réponses étant dit, la surcharge de modèle aurait résolu votre problème; Juste pour répondre directement à votre question, vous pouvez vérifier si le type est une instanciation de boost::optional via un modèle de classe avec spécialisation partielle, par ex.

template <typename> 
struct is_optional : std::false_type {}; 

template <typename T> 
struct is_optional<boost::optional<T>> : std::true_type {}; 

template <typename T> 
void print(const T& o) 
{ 
    static_assert(!is_optional<T>::value, "Please use print_optional instead."); 
    std::cout << o << "\n"; 
} 
1

Juste surcharge print:

template <typename T> 
void print(const T& o) 
{ 
    std::cout << o << "\n"; 
} 

template <typename T> 
void print(const boost::optional<T>& o) 
{ 
    if (o) 
     print(*o); 
    else 
     print("--"); 
} 
5

Vous pouvez tout simplement surcharger la fonction print:

template <typename T> 
void print(const T& o) 
{ 
    std::cout << o << "\n"; 
} 

template <typename T> 
void print(const boost::optional<T>& o) 
{ 
    if (o) 
     print(*o); 
    else 
     print("--"); 
} 

Cela correctement choisir la deuxième surcharge si vous passez un boost::optional, et la première surcharge autrement.

Live demo

+0

En fait, boost variante fait cela hors de la boîte (mais ajoute un espace): http://coliru.stacked-crooked.com/a/bbaa09f05dabfa90 – sehe

+0

@sehe qui est souligné en question :) – TartanLlama

0

Ajout d'une solution non présentée par l'une des anciennes réponses:

Vous pouvez utiliser une struct avec une spécialisation de modèle pour vérifier si le type est optional comme ceci:

template <typename> 
struct is_optional : std::false_type {}; 

template < typename T > 
struct is_optional<std::optional<T>> : std::true_type {}; 

Maintenant, vous pouvez utiliser std::enable_if_t pour avoir une seule méthode qui se comporte différemment pour optional<T> entrées et autres entrées:

template < typename T > 
std::enable_if_t<!is_optional<T>::value, void> print(const T& o) 
{ 
    std::cout << o << "\n"; 
} 

template < typename T > 
std::enable_if_t<is_optional<T>::value, void> print(const T& o) 
{ 
    if (o) 
     print(*o); 
    else 
     print("--"); 
} 

Note: Surcharge de la méthode explicitement pour optional<T> est une meilleure solution, car il est plus propre, plus lisible et ne nécessite pas la structure is_optional, mais c'est néanmoins une implémentation valide.