web-dev-qa-db-fra.com

Existe-t-il une macro __CLASS__ en C ++?

Y a t-il __CLASS__ macro en C++ qui donne un nom de classe similaire à __FUNCTION__ macro donnant le nom de la fonction

85
mortal

Le plus proche consiste à appeler typeid(your_class).name() - mais cela produit un nom mutilé spécifique au compilateur.

Pour l'utiliser à l'intérieur de la classe, il suffit de typeid(*this).name()

60
Aleksei Potov

Le problème avec l'utilisation de typeid(*this).name() est qu'il n'y a pas de pointeur this dans un appel de méthode statique. La macro __PRETTY_FUNCTION__ Indique un nom de classe dans les fonctions statiques ainsi que dans les appels de méthodes. Cependant, cela ne fonctionnera qu'avec gcc.

Voici un exemple d'extraction des informations via une interface de style macro.

inline std::string methodName(const std::string& prettyFunction)
{
    size_t colons = prettyFunction.find("::");
    size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1;
    size_t end = prettyFunction.rfind("(") - begin;

    return prettyFunction.substr(begin,end) + "()";
}

#define __METHOD_NAME__ methodName(__PRETTY_FUNCTION__)

La macro __METHOD_NAME__ Renverra une chaîne de la forme <class>::<method>(), en coupant le type de retour, les modificateurs et les arguments à partir de ce que __PRETTY_FUNCTION__ Vous donne.

Pour quelque chose qui extrait uniquement le nom de la classe, il faut prendre soin de piéger les situations où il n'y a pas de classe:

inline std::string className(const std::string& prettyFunction)
{
    size_t colons = prettyFunction.find("::");
    if (colons == std::string::npos)
        return "::";
    size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1;
    size_t end = colons - begin;

    return prettyFunction.substr(begin,end);
}

#define __CLASS_NAME__ className(__PRETTY_FUNCTION__)
64
Andrew Prock

Pas encore. (Je pense __class__ est proposé quelque part). Vous pouvez également essayer d'extraire une partie de classe de __PRETTY_FUNCTION__.

Je voudrais suggérer boost :: typeindex , ce que j'ai appris de "Effective Modern C++" de Scott Meyer Voici un exemple de base:

Exemple

#include <boost/type_index.hpp>

class foo_bar
{
    int whatever;
};

namespace bti =  boost::typeindex;

template <typename T>
void from_type(T t)
{
    std::cout << "\tT = " << bti::type_id_with_cvr<T>().pretty_name() << "\n";
}

int main()
{
    std::cout << "If you want to print a template type, that's easy.\n";
    from_type(1.0);
    std::cout << "To get it from an object instance, just use decltype:\n";
    foo_bar fb;
    std::cout << "\tfb's type is : "
              << bti::type_id_with_cvr<decltype(fb)>().pretty_name() << "\n";
}

Compilé avec "g ++ --std = c ++ 14", ceci produit ce qui suit

Sortie

Si vous souhaitez imprimer un type de modèle, c'est facile.

T = double

Pour l'obtenir à partir d'une instance d'objet, utilisez simplement decltype:

le type de fb est: foo_bar

9
Spacemoose

Je pense en utilisant __PRETTY_FUNCTION__ est suffisant, même s’il inclut un espace de noms, c.-à-d. namespace::classname::functionname jusqu'à ce que __CLASS__ est disponible.

7
vaibhav

Si votre compilateur se trouve être g++ Et que vous demandez __CLASS__ Parce que vous voulez obtenir le nom de la méthode en cours, classe comprise, __PRETTY_FUNCTION__ Devrait vous aider (selon info gcc, Section 5.43 Noms de fonctions sous forme de chaînes).

3
ndim

Si vous parlez de MS C++ (vous devriez indiquer, surtout comme __FUNCTION__ est une extension non standard), il y a __FUNCDNAME__ et __FUNCSIG__ _ symboles que vous pouvez analyser

2
Ruben Bartelink

Ma solution:

std::string getClassName(const char* fullFuncName)
{
    std::string fullFuncNameStr(fullFuncName);
    size_t pos = fullFuncNameStr.find_last_of("::");
    if (pos == std::string::npos)
    {
        return "";
    }
    return fullFuncNameStr.substr(0, pos-1);
}

#define __CLASS__ getClassName(__FUNCTION__)

Je travaille pour Visual C++ 12.

1
Andrey Epifantsev

Vous pouvez obtenir le nom de la fonction, y compris le nom de la classe. Cela peut traiter des fonctions de type C.

static std::string methodName(const std::string& prettyFunction)
{
    size_t begin,end;
    end = prettyFunction.find("(");
    begin = prettyFunction.substr(0,end).rfind(" ") + 1;
    end -= begin;
    return prettyFunction.substr(begin,end) + "()";
}
1
Charles.Lee

Si vous avez besoin de quelque chose qui produira réellement le nom de la classe lors de la compilation, vous pouvez utiliser C++ 11 pour cela:

#define __CLASS__ std::remove_reference<decltype(classMacroImpl(this))>::type

template<class T> T& classMacroImpl(const T* t);

Je reconnais que ce n’est pas la même chose que __FUNCTION__ _ mais j'ai trouvé ce post en cherchant une réponse comme celle-ci. :RÉ

1
Jon Thompson

Voici une solution basée sur le __FUNCTION__ modèles de macro et C++:

template <class T>
class ClassName
{
public:
  static std::string Get()
  {
    // Get function name, which is "ClassName<class T>::Get"
    // The template parameter 'T' is the class name we're looking for
    std::string name = __FUNCTION__;
    // Remove "ClassName<class " ("<class " is 7 characters long)
    size_t pos = name.find_first_of('<');
    if (pos != std::string::npos)
      name = name.substr(pos + 7);
    // Remove ">::Get"
    pos = name.find_last_of('>');
    if (pos != std::string::npos)
      name = name.substr(0, pos);
    return name;
  }
};

template <class T>
std::string GetClassName(const T* _this = NULL)
{
  return ClassName<T>::Get();
}

Voici un exemple d'utilisation de cette classe pour une classe de consignateur

template <class T>
class Logger
{
public:
  void Log(int value)
  {
    std::cout << GetClassName<T>()  << ": " << value << std::endl;
    std::cout << GetClassName(this) << ": " << value << std::endl;
  }
};

class Example : protected Logger<Example>
{
public:
  void Run()
  {
    Log(0);
  }
}

La sortie de Example::Run sera alors

Example: 0
Logger<Example>: 0
1
Sven Vranckx

Fonctionne aussi avec msvc et gcc

#ifdef _MSC_VER
#define __class_func__ __FUNCTION__
#endif

#ifdef __GNUG__
#include <cxxabi.h>
#include <execinfo.h>
char *class_func(const char *c, const char *f)
{
    int status;
    static char buff[100];
    char *demangled = abi::__cxa_demangle(c, NULL, NULL, &status);
    snprintf(buff, sizeof(buff), "%s::%s", demangled, f);
    free(demangled);
    return buff;
}
#define __class_func__ class_func(typeid(*this).name(), __func__)
#endif
0
Costa

Cela fonctionne assez bien si vous êtes prêt à payer le coût d'un pointeur.

class State 
{
public:
    State( const char* const stateName ) :mStateName( stateName ) {};
    const char* const GetName( void ) { return mStateName; }
private:
    const char * const mStateName;
};

class ClientStateConnected
    : public State
{
public:
    ClientStateConnected( void ) : State( __FUNCTION__ ) {};
};
0
Robert Basler