Is there a __CLASS__ macro in C++ which gives the class name similar to __FUNCTION__ macro which gives the function name
Is there a __CLASS__ macro in C++ which gives the class name similar to __FUNCTION__ macro which gives the function name
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
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.
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