Lors de la création d'une fonction de modèle en C++, existe-t-il un moyen simple de représenter le nom de type du modèle sous forme de chaîne? J'ai un cas de test simple pour montrer ce que j'essaie de faire (notez que le code affiché ne compile pas):
#include <stdio.h>
template <typename type>
type print(type *addr)
{
printf("type is: %s",typename);
}
int main()
{
int a;
print(&a);
}
// Would like to print something like:
// type is: int
Je pense que le nom de type devrait être disponible au moment de la compilation lorsque la fonction est instanciée, mais je ne connais pas très bien les modèles et je ne vois pas comment obtenir le nom de type en tant que chaîne.
La raison pour laquelle je veux faire cela est pour certains débogage de type printf. J'ai plusieurs threads en cours d'exécution et en passant avec gdb modifie le comportement du programme. Donc, pour certaines choses, je veux vider des informations sur les fonctions qui étaient exécutées. Ce n'est pas très important, donc si la solution est trop complexe, j'ignorerais d'ajouter ces informations à ma fonction de journalisation. Mais s'il existait un moyen simple de le faire, il serait utile de disposer d'informations.
__PRETTY_FUNCTION__
devrait résoudre votre problème (au moins au moment de l'exécution)
La sortie du programme ci-dessous est:
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
!!!Hello World!!!
Si vous avez vraiment, vraiment, besoin du nom de type comme chaîne, vous pouvez pirater ceci (en utilisant snprintf
au lieu de printf
) et en tirant la sous-chaîne après '=' et avant ']'.
#include <iostream>
using namespace std;
template<typename type>
class test
{
public:
test()
{
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}
};
template<typename type>
void tempFunction()
{
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}
int main() {
test<int> test;
tempFunction<bool>();
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
return 0;
}
Pour obtenir un nom utile lors de la compilation:
Supposons que vous ayez un type inconnu nommé "T". Vous pouvez faire en sorte que le compilateur imprime son type en l’utilisant horriblement. Par exemple:
typedef typename T::something_made_up X;
Le message d'erreur sera comme:
error: no type named 'something_made_up' in 'Wt::Dbo::ptr<trader::model::Candle>'
Le bit après 'in' montre le type. (Testé uniquement avec clang).
Autres moyens de le déclencher:
bool x = T::nothing; // error: no member named 'nothing' in 'Wt::Dbo::ptr<trader::model::Candle>'
using X = typename T::nothing; // error: no type named 'nothing' in 'Wt::Dbo::ptr<trader::model::Candle>'
Avec C++ 11, vous pouvez déjà avoir un objet et utiliser 'decltype' pour obtenir son type, vous pouvez donc aussi exécuter:
auto obj = creatSomeObject();
bool x = decltype(obj)::nothing; // (Where nothing is not a real member).
Puisque vous avez dit que vous en auriez besoin pour le débogage, une solution d'exécution est peut-être également acceptable. Et vous avez étiqueté ceci en g ++, vous ne voulez donc pas être conforme au standard.
Voici ce que cela signifie:
#include <cxxabi.h> // the libstdc++ used by g++ does contain this header
template <typename type>
void print(const type *addr) // you wanted a pointer
{
char * name = abi::__cxa_demangle(typeid(*addr).name(), 0, 0, NULL);
printf("type is: %s\n", name);
free(name);
}
print(new unsigned long); // prints "type is: unsigned long"
print(new std::vector<int>); // prints "type is: std::vector<int, std::allocator<int> >"
EDIT: corrigé la fuite de mémoire. Merci à Jesse.
Il existe une bibliothèque Boost.TypeIndex.
Voir boost :: typeindex :: type_id pour plus de détails.
Il est très facile à utiliser, multiplate-forme et constitue une véritable solution de type compilation. En outre, cela fonctionne aussi même si aucun RTTI n'est disponible. De plus, la plupart des compilateurs sont pris en charge à partir de la boîte.
Une autre solution de compilation, similaire à celle fournie par -matiu , mais peut-être un peu plus descriptive serait d’utiliser un static_assert
entouré d’une petite fonction d’aide.
template<typename T>
void print_type_in_compilation_error(T&&)
{
static_assert(std::is_same<T, int>::value && !std::is_same<T, int>::value, "Compilation failed because you wanted to read the type. See below");
}
// usage:
int I;
print_type_in_compilation_error(I);
Ce qui précède vous donnera un message d'erreur Nice (testé en MSVC et Clang) comme dans l'autre réponse, mais le code est mieux à mon humble avis de comprendre.
si vous avez un ensemble connu de types utilisés instanciant le modèle, nous pouvons utiliser l'approche décrite dans cet ancien fil de discussion: stackoverflow.com/questions/1055452
Comme commenté par @chris et @Philipp, sauf si vous avez vraiment besoin du nom lors de la compilation, vous pouvez utiliser typeid(type).name()
après avoir inclus <typeinfo>
.