7
votes

Vérifiez si le paramètre Pack contient un type

Je me demandais si C ++ 0x fournit des capacités intégrées pour vérifier si un paquet de paramètres d'un modèle variadique contient un type spécifique. Aujourd'hui, Boost Boost ::: Mpl :: Contient peut être utilisé pour accomplir cela si vous utilisez Boost :: mpl :: vecteur comme substitut des modèles variadiques appropriés. Cependant, il a de graves surcharges de temps de compilation. Je suppose que C ++ 0x dispose d'un support au niveau du compilateur pour STD :: is_same. Je pensais donc si une généralisation comme ci-dessous est également prise en charge dans le compilateur. xxx


0 commentaires

3 Réponses :


7
votes

Non, vous devez utiliser une spécialisation (partielle) avec des modèles variadiques pour calculer des calculs de compilation tels que celui-ci: xxx

Il n'y a qu'une autre opération intrinsèque pour les modèles variadiques et c'est le Formulaire spécial de la taille de l'opérateur de taille qui calcule la longueur de la liste des paramètres, par exemple: xxx

où obtenez-vous "il a de graves heures de temps de compilation" avec boost mpl de? J'espère que vous ne faites pas que faire des hypothèses ici. Boost MPL utilise des techniques telles que l'instanciation de modèles paresseux pour essayer de réduire les temps de compilation au lieu d'exploser comme une méta-programmation de modèle naïf.


5 commentaires

Peut être un ensemble plus important d'opérations intrinsèques doit être soutenu par la langue / le compilateur que celui de la taille de .... (4 points!) IMO, la vérification est aussi «fondamentale» comme trouvant la taille. Je pense que MPL a des frais de performance sur la base de ce test que j'ai écrit. dre.vanderbilt.edu/~suttambe/files/mpl_InterSection.cpppled/a > J'utilise l'algorithme d'intersection codée à la main ainsi que la version de MPL. G ++ 4.4 prend la même heure pour compiler les deux. Les modèles variadiques La version compile 10 fois plus rapidement. BTW, pouvez-vous me suggérer de lire sur la technique de l'instanciation des modèles paresseux de MPL?


J'ai trouvé de bons exemples d'évaluation paresseuse dans le livre de métaprogramming de modèle C ++. N'est-ce pas évident ?! Merci quand même.


YEP Tout ce que vous avez à faire est d'éviter l'instanciation des modèles d'une méta-fonctions (en exposant le type d'alias de type imbriqué ») avant de donner le résultat à une autre méta-fonctions de boost. Boost Meta-Fonctions ont été conçues pour évaluer les méta-fonctions à très dernier moment, l'alias de type imbriqué est nécessaire. Vous devez également essayer d'éviter les valeurs nues et utilisez les wrappers de type méta-data (comme MPL :: Bool_) car ils sont conçus pour travailler de manière paresseusement. Parfois Boost Boost Mpl fournit deux formes de Une méta-fonction, essayez d'utiliser celui qui favorise l'instanciation paresseuse.


Je sens cela une réponse plus abordable à cause de sa simplicité!


Je préférerais utiliser des techniques de spécialisation pour la correspondre: Modèle STREST C: STD :: FALSE_TYPE {}; Modèle structure C : STD :: true_type {}; Modèle STRUCT C : C {};



2
votes

Si vous souhaitez éviter la récursion de type manuelle, std :: common_type me semble être le seul utilitaire de la STL qui est un modèle variadique, et donc le seul qui pourrait potentiellement encapsuler une récursivité .


solution 1

std :: common_type trouve le type le moins dérivé dans un ensemble de types. Si nous identifions des numéros avec des types, des nombres spécifiquement élevés avec des types moins dérivés, il trouve le plus grand nombre d'un ensemble. Ensuite, nous devons mapper l'égalité sur le type de clé sur un niveau de dérivation. xxx


solution 2

Nous pouvons pirater common_type un peu plus. La norme dit

Un programme peut spécialiser ce trait si au moins un paramètre de modèle dans le La spécialisation est un type défini par l'utilisateur.

Et décrit exactement ce qui se trouve à l'intérieur: un étui de spécialisation partiel récursif, une affaire qui applique un opérateur binaire et un cas de terminal. Essentiellement, c'est une fonction générique pli et vous pouvez ajouter n'importe quelle opération binaire. Ici, j'ai utilisé l'ajout parce qu'il est plus informatif que ou. Notez que is_same renvoie un integral_constant . xxx


4 commentaires

Celui-ci est un casse-tease de cerveau. Mais j'ai aimé ça! Assume une bonne compréhension du trait commun_type. Je devais la creuser dans le projet public C ++ 0X. Combinant cela avec une conversion implicite en base_one via Type_equal est intelligent. C ++ n'a que trop de ces astuces intelligentes. Peut-on faire quelque chose de plus intuitif d'utiliser STD :: is_same et logique - ou d'une manière ou d'une autre?


C'est un peu mieux mais les détails d'engourdissement de l'esprit doivent être internalisés.


@Alexandre: merci. En fait, je fais une programmation fonctionnelle et je me demandais exactement cela! Je ne me souvenais pas parce que Python appelle cela Réduire et c ++ appelle IT accumuler .


@Potatoswatter: Zip prend deux listes et renvoie une liste de paires (d'où le nom "zip").



14
votes

Heureusement, la norme C ++ a évolué. Avec C ++ 1Z AKA C ++ 17, vous pouvez enfin itérer facilement les paquets de paramètres. Donc, le code de la réponse est (presque) aussi simple, comme suggéré dans la question: xxx pré>

le bizarre (std :: is_same_v ||. ..) code> est développé par le compilateur en interne à (std :: isame_v || std :: is_same_v || ...) code>, ce qui est exactement, ce que vous voulez. Il donne même correctement correctement faux code> avec un paquet de paramètres code> vide code>. P>

Il est même possible de faire tout le contrôle en ligne dans une fonction ou une méthode - non Les structures d'assistance sont nécessaires: P>

template<typename T, typename ... List>
void foo(T t, List ... lst)
{
    if constexpr((std::is_same_v<T, List> || ...)) {
        std::cout << "T is in List" << std::endl;
    } else {
        std::cout << "T is not in List" << std::endl;
    }
}


1 commentaires

Belle solution. Il peut être simplifié un peu: Modèle consexpr inline bool is_present_v = (std :: is_same_v || ...);