C++ Obtenir le nom du type, modèle
Je suis en train d'écrire certaines classes de modèle pour parseing certains fichiers de données texte, et en tant que tel, il est likly la grande majorité des erreurs d'analyse vont être due à des erreurs dans le fichier de données, qui sont pour la plupart écrits par des programmeurs, et donc besoin d'un gentil message sur les raisons de l'application a échoué à charge par exemple quelque chose comme:
Erreur d'analyse example.txt. Valeur ("notaninteger")de [MySectiom]Clé n'est pas valide int
Je peux travailler sur le fichier, l'article et les noms de clés à partir d'arguments passés à la fonction de modèle et membre de vars dans la classe, mais je ne suis pas sûr de la façon d'obtenir le nom du type de la fonction de modèle est d'essayer de convertir de.
Mon code actuel ressemble, avec des spécialités pour de simples chaînes de caractères et tel:
template<typename T> T GetValue(const std::wstring §ion, const std::wstring &key)
{
std::map<std::wstring, std::wstring>::iterator it = map[section].find(key);
if(it == map[section].end())
throw ItemDoesNotExist(file, section, key)
else
{
try{return boost::lexical_cast<T>(it->second);}
//needs to get the name from T somehow
catch(...)throw ParseError(file, section, key, it->second, TypeName(T));
}
}
Id plutôt pas des surcharges pour chaque type que les fichiers de données peuvent utiliser, puisqu'il y a des tas d'entre eux...
Aussi j'ai besoin d'une solution qui n'engage pas de gestion d'exécution, sauf si une exception se produit, c'est à dire une compilation complète d'une solution en temps est ce que je veux puisque ce code est appelé tonnes de fois et de temps de chargement sont déjà à faire un peu long.
EDIT: Ok c'est la solution je suis venu avec:
J'ai un types.h contient les éléments suivants
#pragma once
template<typename T> const wchar_t *GetTypeName();
#define DEFINE_TYPE_NAME(type, name) \
template<>const wchar_t *GetTypeName<type>(){return name;}
Alors je peux utiliser le DEFINE_TYPE_NAME macro au rpc fichiers pour chaque type j'ai besoin de traiter (par exemple, dans le fichier cpp qui ont défini le type de départ).
L'éditeur de liens est alors en mesure de trouver la appropirate modèle de spécialisation, tant qu'il a été défini quelque part, ou de jeter un linker error autrement de sorte que je peux ajouter le type.
- pas vraiment pertinentes à votre question, mais vous pourriez vouloir utiliser la carte.trouver(section) lors de l'accès à la section aswell, sauf si vous souhaitez volontairement pour créer une section vide.
Vous devez vous connecter pour publier un commentaire.
Jesse Beder la solution est probablement la meilleure, mais si vous n'aimez pas les noms typeid vous donne (je pense que gcc vous donne les noms déformés par exemple), vous pouvez faire quelque chose comme:
Et de l'utiliser ensuite comme
EDIT:
Vous pouvez également combiner les deux, changement
name
à une fonction qui, par défaut, les appelstypeid(T).name()
et ensuite seulement de se spécialiser dans les cas où ce n'est pas acceptable.error: '#' is not followed by a macro parameter
La solution est
qui renvoie std::type_info.
typeid(simd::double3x4).name() = "N4simd9double3x4E"
.typeid(simd::float4).name() = "Dv4_f"
C++17, Xcode 10.1.typeid(T).name()
la mise en œuvre est définie et ne garantit pas lisible par les humains à la chaîne.Lecture cppreference.com :
Mais dans certains cas, gcc n'a pas de droit de retour de la chaîne. Par exemple sur ma machine j'ai le gcc avec
-std=c++11
et à l'intérieur du modèle de la fonctiontypeid(T).name()
retourne"j"
pour"unsigned int"
. C'est donc appelé déformés nom. Pour prendre un vrai nom de type, l'utilisationabi::__cxa_demangle() fonction (gcc uniquement):
free
dansif
?nullptr
si le statut n'est pas 0.Comme mentionné par Bunkar typeid(T).nom de la mise en œuvre est définie.
Pour éviter ce problème, vous pouvez utiliser Coup de pouce.TypeIndex bibliothèque.
Par exemple:
boost
de nouveau pour la victoire. incroyable ce boost ne sans prise en charge du compilateur (auto
,regex
,foreach
,threads
,static_assert
, etc, etc... le support avant de compilateurs/C++-support de la norme).La réponse de Logan Capaldo est correct, mais peut être légèrement simplifiée, car il est inutile de se spécialiser la classe de tous les temps. On peut écrire:
Cela vous permet également de mettre le REGISTER_PARSE_TYPE instructions dans un fichier C++...
Comme la reformulation de Andrey réponse:
La Boost TypeIndex bibliothèque peut être utilisée pour imprimer les noms de types.
À l'intérieur d'un modèle, ce qui pourrait se lire comme suit
Je viens de l'y laisser.
Si quelqu'un va en avoir besoin, alors vous pouvez utiliser ceci:
Cela ne fera que VÉRIFIER le type de ne pas l'OBTENIR et uniquement pour le type 1 ou 2.
Si vous souhaitez un pretty_name, Logan Capaldo, la solution ne peut pas traiter avec structure de données complexes:
REGISTER_PARSE_TYPE(map<int,int>)
et
typeid(map<int,int>).name()
me donne un résultat deSt3mapIiiSt4lessIiESaISt4pairIKiiEEE
Il y a une autre réponse intéressante à l'aide de
unordered_map
oumap
vient de https://en.cppreference.com/w/cpp/types/type_index.