web-dev-qa-db-fra.com

Comment convertir typename T en chaîne en c ++

Tout en jouant avec les modèles dans c ++, j’ai rencontré un problème de conversion de typename T en chaîne. Par exemple:

template <typename T>
class Matrix {
   public:
        Matrix() {
           //my_type = string type of T. i.e. if T is char. I want my_type to be "char".
        }
   string my_type;
}

Comment puis-je convertir T en une chaîne qui dit ce que T est.

Remarque: je suis en train de jouer, alors ne vous inquiétez pas si vous en avez besoin.

53
Srikanth

Il n'y a pas de mécanisme intégré pour cela. typeid(T)::name() peut donner des informations, mais la norme ne stipule pas que cette chaîne doit être lisible par un humain; juste distinct pour chaque type. Microsoft Visual C++ utilise des chaînes lisibles par l'homme; GCC ne le fait pas.

Vous pouvez cependant construire votre propre système. Par exemple, basé sur les traits. Quelque chose comme ça:

// default implementation
template <typename T>
struct TypeName
{
    static const char* Get()
    {
        return typeid(T).name();
    }
};

// a specialization for each type of those you want to support
// and don't like the string returned by typeid
template <>
struct TypeName<int>
{
    static const char* Get()
    {
        return "int";
    }
};

// usage:
const char* name = TypeName<MyType>::Get();
56
atzz

Pour GCC, vous devez utiliser une astuce. En utilisant cxxabi.h .__, j’ai écrit un petit wrapper à cet effet.

#include <string>
#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <cxxabi.h>

#define DEBUG_TYPE(x) do { typedef void(*T)x; debug_type<T>(T(), #x); } while(0)

template<typename T>
struct debug_type
{
    template<typename U>
    debug_type(void(*)(U), const std::string& p_str)
    {
        std::string str(p_str.begin() + 1, p_str.end() - 1);
        std::cout << str << " => ";
        char * name = 0;
        int status;
        name = abi::__cxa_demangle(typeid(U).name(), 0, 0, &status);
        if (name != 0) { std::cout << name << std::endl; }
        else { std::cout << typeid(U).name() << std::endl; }
        free(name);
    }
};

Double parentheis est nécessaire. Fonctionne avec n'importe quel type.

Maintenant, vous pouvez l’utiliser pour boost :: mpl:

DEBUG_TYPE((if_c<true, true_, false_>::type));

sera imprime:

if_c<true, true_, false_>::type => bool_<true>
19

Vous ne pouvez pas, du moins pas directement. Le seul moyen de convertir un jeton ou une série de jetons en un littéral de chaîne consiste à utiliser l'opérateur de stringization du préprocesseur (#) à l'intérieur d'une macro. 

Si vous voulez obtenir un littéral de chaîne représentant le type, vous devrez écrire quelque chose vous-même, peut-être en utilisant une macro pour instancier le modèle et lui passer le nom du type sous forme de chaîne.

Un problème avec toute approche générale est: quelle chaîne devrait être donnée pour les utilisations suivantes:

Matrix<char> x;
typedef char MyChar;
Matrix<MyChar> y;

x et y sont du même type, mais l’un utilise directement char et l’autre utilise le typedef MyChar.

6
James McNellis

façon de contourner ...

#define Tprint(x) print<x>(#x)

template<typename T>
void print (string ltype){
cout<<ltype<<" = "<<sizeof(T)<<endl;
}
2
user3071398

Il est impossible d'obtenir le nom du type dans string si le type est l'un des types de base. Pour les types définis par l'utilisateur, vous pouvez utiliser typeid(my_type).name(). Aussi vous avez besoin de #include <typeinfo>:) plus d'infos ...

2
Mihran Hovsepyan

Vous pouvez utiliser une bibliothèque de réflexion C++ . Alors:

using namespace ponder;

Class::declare<Matrix>();

std::string const& name = classByType<Matrix>().name();

Cela vous donne également d'autres options une fois que vous avez les informations sur la métaclasse, telles que la recherche de ce que sont les membres du groupe.

0
Nick