Is there a __CLASS__ macro in C++?
Asked Answered
P

16

139

Is there a __CLASS__ macro in C++ which gives the class name similar to __FUNCTION__ macro which gives the function name

Polydactyl answered 3/11, 2009 at 11:42 Comment(0)
E
76

The closest thing there's is to call typeid(your_class).name() - but this produces compiler specific mangled name.

To use it inside class just typeid(*this).name()

Emmer answered 3/11, 2009 at 11:44 Comment(8)
You have to know your class first to invoke this ;-)Definitive
this is for logging, so I do know the class where I am invoking this. Just trying to avoid explicitly defining a char array containing the class namePolydactyl
typeid(*this).name() can be used inside class functionsEmmer
That's better. As for knowing the class, defining char array sounds better than postponing it till runtime.Definitive
That's a pity it isn't defined like __ CLASS __ , it can be handy at preprocessor stage! :(Hakon
@kexik Preprocessor doesn't know anything about classes.Dirham
@Dirham It doesn't but could. The similar way it knows about functions :-PHakon
@kexik: the preprocessor doesn't know about functions either, standard __func__ and non-standard __FUNCTION__ aren't macros. Microsoft documents __FUNCTION__ as a macro, but the giveaway that it isn't really, is that it's not expanded by the preprocessor when you compile with /P.Popele
M
95

The problem with using typeid(*this).name() is that there is no this pointer in a static method call. The macro __PRETTY_FUNCTION__ reports a class name in static functions as well as method calls. However, this will only work with gcc.

Here's an example of extracting the information through a macro style interface.

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__)

The macro __METHOD_NAME__ will return a string of the form <class>::<method>(), trimming the return type, modifiers and arguments from what __PRETTY_FUNCTION__ gives you.

For something which extracts just the class name, some care must be taken to trap situations where there is no class:

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__)
Microvolt answered 2/4, 2013 at 22:24 Comment(7)
Shouldn't you surround this with #ifdef __GNU_C__ ?Interrogatory
instead of substr(0,colons).rfind(" ") one could use rfind(' ', colons) to spare a creation of an extra string.Redwing
I'd rather use find_last_of("::") Otherwise the function will only return a namespace if there is onePostrider
I wrote a possibly wider scope version of the __METHOD_NAME__ macro. Check here.Anna
In C++11 you could try to make this a constexpr function to evaluate it at compile timeNeustria
andre-holzner: See my solution for a constexpr version.Underestimate
if you want constexpr, std::string_view should be used instead of std::string. std::string_view needs C++17Fordham
E
76

The closest thing there's is to call typeid(your_class).name() - but this produces compiler specific mangled name.

To use it inside class just typeid(*this).name()

Emmer answered 3/11, 2009 at 11:44 Comment(8)
You have to know your class first to invoke this ;-)Definitive
this is for logging, so I do know the class where I am invoking this. Just trying to avoid explicitly defining a char array containing the class namePolydactyl
typeid(*this).name() can be used inside class functionsEmmer
That's better. As for knowing the class, defining char array sounds better than postponing it till runtime.Definitive
That's a pity it isn't defined like __ CLASS __ , it can be handy at preprocessor stage! :(Hakon
@kexik Preprocessor doesn't know anything about classes.Dirham
@Dirham It doesn't but could. The similar way it knows about functions :-PHakon
@kexik: the preprocessor doesn't know about functions either, standard __func__ and non-standard __FUNCTION__ aren't macros. Microsoft documents __FUNCTION__ as a macro, but the giveaway that it isn't really, is that it's not expanded by the preprocessor when you compile with /P.Popele
D
12

Not yet. (I think __class__ is proposed somewhere). You can also try to extract class part from __PRETTY_FUNCTION__.

Definitive answered 3/11, 2009 at 11:46 Comment(0)
G
11

I would like to suggest boost::typeindex, which I learned about from Scott Meyer's "Effective Modern C++" Here's a basic example:

Example

#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";
}

Compiled with "g++ --std=c++14" this produces the following

Output

If you want to print a template type, that's easy.

T = double

To get it from an object instance, just use decltype:

fb's type is : foo_bar

Glint answered 27/8, 2015 at 13:27 Comment(1)
Is it possible to get just class name without namespaces with this? aka coliru.stacked-crooked.com/a/cf1b1a865bb7ecc7Solander
T
8

I think using __PRETTY_FUNCTION__ is good enough though it includes namespace as well i.e. namespace::classname::functionname until __CLASS__ is available.

Tourmaline answered 29/4, 2013 at 3:37 Comment(0)
H
7

If you need something that will actually produce the class name at compile time, you can use C++11 to do this:

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

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

I recognize that this is not the same thing as __FUNCTION__ but I found this post while looking for an answer like this. :D

Hayner answered 27/4, 2018 at 17:1 Comment(3)
This is the best solution I've seen so far! It needs to be at compile time, not runtime!Plasma
Compile error, I tried on GCC-11, with option -std=gnu++20Fordham
It just gets the type of the class, not the string representationFordham
U
6

I created a function using __PRETTY_FUNCTION__ and constexpr with C++17 constexpr std::string_view methods. I also updated the algorithm a bit to be more reliably (Thanks to @n. 'pronouns' m for your help in 64387023).

constexpr std::string_view method_name(const char* s)
{
    std::string_view prettyFunction(s);
    size_t bracket = prettyFunction.rfind("(");
    size_t space = prettyFunction.rfind(" ", bracket) + 1;
    return prettyFunction.substr(space, bracket-space);
}
#define __METHOD_NAME__ method_name(__PRETTY_FUNCTION__)

In C++20, one can declare the function as consteval forcing it to evaluate at compile-time. Furthermore, there is std::basic_fixed_string for use as template parameter.

Underestimate answered 16/10, 2020 at 7:42 Comment(1)
This is the best answer, get you wanted at compile timeFordham
C
4

If your compiler happens to be g++ and you are asking for __CLASS__ because you want a way to get the current method name including the class, __PRETTY_FUNCTION__ should help (according to info gcc, section 5.43 Function Names as Strings).

Commentary answered 3/11, 2009 at 11:52 Comment(0)
P
3

You can get the function name including class name. This can process C-type funcitons.

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) + "()";
}
Pushball answered 14/5, 2013 at 3:19 Comment(0)
C
2

If you're talking MS C++ (You should state, esp as __FUNCTION__ is a non-standard extension), there are __FUNCDNAME__ and __FUNCSIG__ symbols which you could parse

Clancy answered 3/11, 2009 at 11:48 Comment(0)
S
1

My 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__)

I works for Visual C++ 12.

Sometime answered 14/11, 2014 at 9:21 Comment(0)
M
1

Here's a solution based on the __FUNCTION__ macro and C++ templates:

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();
}

Here's an example of how this could be used for a logger class

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);
  }
}

The output of Example::Run will then be

Example: 0
Logger<Example>: 0
Malinowski answered 22/1, 2015 at 12:29 Comment(1)
Note that this will not take into account polymorphism if you have a pointer-to-base (which is probably fine).Langlois
G
0

This works quite nicely if you are willing to pay the cost of a pointer.

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__ ) {};
};
Gramme answered 26/4, 2015 at 6:44 Comment(0)
A
0

Works with msvc and gcc too

#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
Ardellardella answered 19/11, 2015 at 10:52 Comment(1)
What about clang?Baalman
M
0

All the solutions posted above that rely on the __PRETTY_FUNCTION__ do have specific edge case(s) where they do not return the class name / class name only. For example, consider the following pretty function value:

static std::string PrettyFunctionHelper::Test::testMacro(std::string)

Using the last occurence of "::" as delimter won't work since the function parameter also contains a "::" (std::string). You can find similar edge cases for "(" as delimiter and more. The only solution I found takes both the __FUNCTION__ and __PRETTY_FUNCTION__ macros as parameters. Here is the full code:

namespace PrettyFunctionHelper{
    static constexpr const auto UNKNOWN_CLASS_NAME="UnknownClassName";
    /**
     * @param prettyFunction as obtained by the macro __PRETTY_FUNCTION__
     * @return a string containing the class name at the end, optionally prefixed by the namespace(s).
     * Example return values: "MyNamespace1::MyNamespace2::MyClassName","MyNamespace1::MyClassName" "MyClassName"
     */
    static std::string namespaceAndClassName(const std::string& function,const std::string& prettyFunction){
        //AndroidLogger(ANDROID_LOG_DEBUG,"NoT")<<prettyFunction;
        // Here I assume that the 'function name' does not appear multiple times. The opposite is highly unlikely
        const size_t len1=prettyFunction.find(function);
        if(len1 == std::string::npos)return UNKNOWN_CLASS_NAME;
        // The substring of len-2 contains the function return type and the "namespaceAndClass" area
        const std::string returnTypeAndNamespaceAndClassName=prettyFunction.substr(0,len1-2);
        // find the last empty space in the substring. The values until the first empty space are the function return type
        // for example "void ","std::optional<std::string> ", "static std::string "
        // See how the 3rd example return type also contains a " ".
        // However, it is guaranteed that the area NamespaceAndClassName does not contain an empty space
        const size_t begin1 = returnTypeAndNamespaceAndClassName.rfind(" ");
        if(begin1 == std::string::npos)return UNKNOWN_CLASS_NAME;
        const std::string namespaceAndClassName=returnTypeAndNamespaceAndClassName.substr(begin1+1);
        return namespaceAndClassName;
    }
    /**
     * @param namespaceAndClassName value obtained by namespaceAndClassName()
     * @return the class name only (without namespace prefix if existing)
     */
    static std::string className(const std::string& namespaceAndClassName){
        const size_t end=namespaceAndClassName.rfind("::");
        if(end!=std::string::npos){
            return namespaceAndClassName.substr(end+2);
        }
        return namespaceAndClassName;
    }
    class Test{
    public:
        static std::string testMacro(std::string exampleParam=""){
            const auto namespaceAndClassName=PrettyFunctionHelper::namespaceAndClassName(__FUNCTION__,__PRETTY_FUNCTION__);
            //AndroidLogger(ANDROID_LOG_DEBUG,"NoT2")<<namespaceAndClassName;
            assert(namespaceAndClassName.compare("PrettyFunctionHelper::Test") == 0);
            const auto className=PrettyFunctionHelper::className(namespaceAndClassName);
            //AndroidLogger(ANDROID_LOG_DEBUG,"NoT2")<<className;
            assert(className.compare("Test") == 0);
            return "";
        }
    };
}
#ifndef __CLASS_NAME__
#define __CLASS_NAME__ PrettyFunctionHelper::namespaceAndClassName(__FUNCTION__,__PRETTY_FUNCTION__)
#endif
Monograph answered 11/7, 2020 at 8:57 Comment(0)
U
-2

Following method (based on methodName() above) can also handle input like "int main(int argc, char** argv)":

string getMethodName(const string& prettyFunction)
{
    size_t end = prettyFunction.find("(") - 1;
    size_t begin = prettyFunction.substr(0, end).rfind(" ") + 1;

    return prettyFunction.substr(begin, end - begin + 1) + "()";
}
Urbanna answered 9/2, 2017 at 13:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.