Stringifying arguments de modèle
Est-il possible en C++ de stringify arguments de modèle?
J'ai essayé ceci:
#define STRINGIFY(x) #x
template <typename T>
struct Stringify
{
Stringify()
{
cout<<STRINGIFY(T)<<endl;
}
};
int main()
{
Stringify<int> s;
}
Mais ce que je reçois est un " T "et non un "int". Semble que les préprocesseurs coups de pied en avant le modèle de résolution.
Est-il un autre moyen pour ce faire?
Est-il de toute façon pour le prétraitement de prendre place après le modèle de résolution? (Compilateur VC++).
- Modèle de résolution des coups de pied dans, longtemps après le préprocesseur fait son travail. De toute façon, les modèles sont beaucoup plus que le texte de substitution (eh bien, ce n'est même pas de texte de substitution), afin de changer l'ordre des opérations, il ne serait pas à résoudre votre problème.
- Le préprocesseur coups de pied en avant à peu près tout. D'où le nom de avant-processeur.
- J'ai vu des gens faire
template<typename T> char const* get_type_name() { return __PRETTY_FUNCTION__; }
puis extraire leT = ...
de la chaîne. - Macro d'extension qui se passe longtemps avant que le compilateur s'en mêle.
- un hack sympa, mais pourquoi ne pas poster comme réponse, donc je peux upvote qui? 🙂
- Je crains que je n'étais pas sûr de savoir si cela fonctionne avec VC++ xD
- Je présume que les
T
extrait de__PRETTY_FUNCTION__
ressemblera beaucouptypeid(T).name()
. Pourquoi les rédacteurs de compilateur de mettre en œuvre des algorithmes différents pour représenter les types? - Parce que
__PRETTY_FUNCTION__
est conçu pour être lisible par l'homme (dans les messages de débogage - il a le même format que dans les diagnostics afaics), tandis quetypeid(T).name()
ne l'est pas. - Eh bien,
typeid(T).name()
n'est pas nécessaire de retourner quelque chose de valable, mais je reçois votre point de vue. Travaillant essentiellement avec les VC et à l'aide detypeid(T).name()
surtout pour les petits programmes de test, j'oublie qu'il n'a pas à renvoyer un bien mis en forme type. - assez bien mais pas vraiment tout. avant de prétraiter il est oblique style de fin de ligne et triggraphs.
- trigraph de remplacement et de la ligne d'épissage sont les deux premières phases du préprocesseur.
- Est-ce à dire que, sous les auspices de la VC,
typeid(T).name()
renvoie une demangled nom du type de rapport en vertu de la clang ou gcc égide, dans ce cas, vous devez utiliser, par exemple,abi::__cxa_demangle()
pour obtenir quelque chose de “bien formaté” ?... Je n'ai jamais utilisé de VC, et qui pique ma curiosité.
InformationsquelleAutor sold | 2009-09-28
Vous devez vous connecter pour publier un commentaire.
Vous pouvez essayer de
Modifier: Fixe basé sur les commentaires.
name()
, mais la plupart le font.typeid()
, pastypeinfo()
- le second est le nom de l'en-tête<typeinfo>
, et aussistd::type_info
est le type de classe de l'objet renvoyé partypeid()
.Vous pourriez utiliser certains modèles de la magie.
Ce qui a un avantage sur le RTTI (c'est à dire
typeinfo
) - il est résolu lors de la compilation; et un inconvénient - vous besoin de fournir des informations de type de vous-même (à moins qu'il y est une bibliothèque qui n'a déjà que je ne suis pas au courant; peut-être quelque chose de suralimentation même).Ou, comme Matrin York suggéré dans les commentaires, l'utilisation de la fonction inline modèles au lieu:
Mais, si vous avez besoin de stocker plus d'informations sur ce type particulier, puis la classe de modèles sera probablement mieux.
#define TYPE_STRING(T) template<> const char* TypeName<T>::name = STRINGIFY(T)
Votre code ne fonctionne pas parce que le préprocesseur, responsable de la recherche et de l'expansion des macros que vous utilisez dans votre code, n'est pas au courant de la langue elle-même. C'est juste un texte de l'analyseur. Il trouve que STRINGIFY(T) en fonction du modèle et de la développer, beaucoup avant de vous donner un type à ce modèle. Comme il s'avère, vous obtiendrez toujours de "T" à la place de la typename vous attend, malheureusement.
Comme litb suggéré, j'ai la (mal) mis en œuvre cette "getTypeName' modèle de fonction qui retourne le nom du type de vous passer:
Le code ci-dessus les résultats dans la sortie suivante avec GCC drapeau -s ("bande de tous les symboles de binary") activé:
Donc, voyez-vous, getTypename() fournit un assez mieux, au coût de fugly d'analyse de chaînes de hack (je SAIS, c'est sacrément moche).
Quelques points à prendre en compte:
__PRETTY_FUNCTION__
's différemment, la correspondance de chaîne peut se briser et vous devrez le réparer. Pour cette même raison, j'ai aussi avertir que getTypeName() pourrait être bon pour le débogage (et, encore, peut-être même pas bon pour ça), mais il est sûrement mauvais, mauvais, et mauvais pour d'autres fins, telles que la comparaison de deux types dans un modèle ou quelque chose comme ça (je ne sais pas, juste deviner ce que quelqu'un pourrait penser..). L'utiliser uniquement à des fins de débogage, et de préférence ne pas l'appeler dans les versions release (utiliser des macros pour désactiver), de sorte que vous n'utilisez pas__PRETTY_FUNCTION__
et donc le compilateur ne produit pas la chaîne pour elle.En dépit de ces inconvénients, je tiens à dire que c'est sûr qu'il est rapide. Pour la deuxième fois, vous recherche pour un même type de nom, il vous en coûtera sélection d'une référence à un plan global de std::string contenant le nom. Et, comparativement au modèle specialiazation méthodes suggérées avant, il n'y a rien d'autre à déclarer en plus de la très modèle lui-même, de sorte qu'il est vraiment beaucoup plus facile à utiliser.
strlen
, pourquoi ne pas utiliserconst char beginStr[] = "_Get_TypeName =";
qui vous permettrait d'utilisersizeof
à moins qu'il se désintègre à un pointeur.getTypeName<string>()
imprimestd::basic_string<char, std::char_traits<char>, std::allocator<char>>
.Non, vous ne pouvez pas travailler sur des types comme s'ils étaient des variables. Vous pouvez écrire du code qui extrait les typeid() d'un élément et d'imprimer le nom, mais la valeur qui en résulte ne sera probablement pas ce que vous attendez (type de noms ne sont pas standarized).
Vous pouvez également travailler avec des spécialisations de modèle (et de certains macro magique) pour arriver à une version intéressante si le nombre de types que vous voulez travailler avec est limitée:
Ou vous pouvez même combiner les deux versions: mettre en œuvre le printtype modèle générique à l'aide de typeinfo et de fournir ensuite des spécialisations pour les types que vous voulez avoir des noms fantaisistes.
Ce qui supprimera l'un de mes principes de base en matière de code de C++ écrit: Évitez d'utiliser des astuces dans les deux fonctionnalités de modèle et le préprocesseur en même temps.
Partie de la raison pour les modèles et la méchanceté qu'ils introduisent dans la langue était une tentative de sevrage aux développeurs d'utiliser le préprocesseur. Si vous utilisez à la fois, puis les terroristes gagner.
Si vous utilisez le boost/core/demangle.php, vous pouvez obtenir un fiable et lisible de la chaîne.
Voici ce que je fais: j'ai un
demangle()
fonction (mise en œuvre sur le dessus deabi::__cxa_demangle()
que j'appelle avec un couple de commodité fonction de modèle surcharge,nameof()
, avec le type, je veux stringified ou une instance de même.Il est assez compact, donc je vais reproduire ici dans toute sa gloire. Dans
demangle.hh
nous avons:... Et puis dans
demangle.cpp
:Pour l'utiliser, je pense que vous aurez un lien pour
libc++
(ou quel que soit votre équivalent local), pour utiliserabi::__cxa_demangle()
. Ce peut être sous-optimale pour l'OP, c'est le fait que cela ne le demangling et stringification au moment de l'exécution. Je serais personnellement l'amour quelque chose deconstexpr
-friendly en leu de cela, mais depuis je souffre d'une grave macro-abus d'allergie, je trouve cela pour le moins, de façon générale déraisonnable solution à ce problème.(le
terminator
espace de noms n'est pas sans conséquence – je utiliser ce code dans un libunwind à base de stacktracer appelé à partir de la cessation de gestionnaire – n'hésitez pas às///g
le jeton)dans mon code j'utilise le "terrible" double-déclaration de la "Classe-Nom"
parce que le c++ n'est PAS en mesure d'extraire la chaîne "Monserveur" à partir du modèle...
le seul "moyen" pour se "débarrasser" de ce... à l'aide d'un rpc "wrapper"