C ++中是否有__CLASS__宏?

时间:2009-11-03 11:42:45

标签: c++ macros

C ++中是否有一个__CLASS__宏,它给出类似于__FUNCTION__宏的类名,它给出了函数名称

16 个答案:

答案 0 :(得分:61)

使用typeid(*this).name()的问题是静态方法调用中没有this指针。宏__PRETTY_FUNCTION__报告静态函数中的类名以及方法调用。但是,这只适用于gcc。

以下是通过宏样式界面提取信息的示例。

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

__METHOD_NAME__将返回<class>::<method>()形式的字符串,修剪__PRETTY_FUNCTION__给你的返回类型,修饰符和参数。

对于只提取类名的内容,必须注意陷阱没有类的情况:

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

答案 1 :(得分:59)

最接近的是调用typeid(your_class).name() - 但这会产生编译器特定的受损名称。

在课堂内typeid(*this).name()

使用它

答案 2 :(得分:9)

还没有。 (我认为__class__是在某处提出的)。您还可以尝试从__PRETTY_FUNCTION__中提取类部分。

答案 3 :(得分:9)

我想建议boost::typeindex,我从Scott Meyer&#34;有效的现代C ++&#34;这是一个基本的例子:

示例

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

编译用&#34; g ++ --std = c ++ 14&#34;这产生以下

<强>输出

  

如果您想打印模板类型,那很简单。

     

T = double

     

要从对象实例获取它,只需使用decltype:

     

fb的类型是:foo_bar

答案 4 :(得分:6)

我认为使用__PRETTY_FUNCTION__已经足够了,但它包括名称空间,即namespace::classname::functionname,直到__CLASS__可用。

答案 5 :(得分:3)

如果您的编译器恰好是g++并且您要求__CLASS__,因为您想要获取包含该类的当前方法名称,__PRETTY_FUNCTION__应该有所帮助(根据{ {1}}, 5.43函数名称为字符串)。

答案 6 :(得分:2)

如果您正在谈论MS C ++(您应该声明,尤其是__FUNCTION__是非标准扩展名),您可以解析__FUNCDNAME__ and __FUNCSIG__ symbols

答案 7 :(得分:1)

您可以获取包含类名的函数名称。 这可以处理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) + "()";
}

答案 8 :(得分:1)

我的解决方案:

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

我在Visual C ++ 12工作。

答案 9 :(得分:1)

这是基于__FUNCTION__宏和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();
}

以下是一个如何将其用于记录器类的示例

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

Example::Run的输出将是

Example: 0
Logger<Example>: 0

答案 10 :(得分:1)

如果您需要在编译时实际生成类名的内容,可以使用C ++ 11执行此操作:

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

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

我认识到这与__FUNCTION__不是一回事,但我在寻找这样的答案时发现了这篇文章。 :d

答案 11 :(得分:0)

如果您愿意支付指针的费用,这非常有效。

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

答案 12 :(得分:0)

也适用于msvc和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

答案 13 :(得分:0)

上面发布的所有依赖__PRETTY_FUNCTION__的解决方案都具有特定的边缘情况,在这些情况下,它们不仅返回类名/类名。例如,考虑以下漂亮的函数值:

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

由于功能参数还包含"::""::",因此不能将std::string的最后一次出现用作分行符。 您可以在"("中找到类似的边缘情况作为分隔符,甚至更多。 我发现的唯一解决方案同时使用__FUNCTION____PRETTY_FUNCTION__宏作为参数。这是完整的代码:

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

答案 14 :(得分:0)

我使用object FindingMaximum { val spark = SparkSession .builder() .appName("FindingMaximum") .master("local[*]") .getOrCreate() val sc = spark.sparkContext case class Posting(key: Int, value: Long, value2: Option[Long], value3: Int, value4: Option[Int]) val data = List((Some(23661587),Seq(Posting(2,23661643,Some(23661587),0,None), Posting(2,23661682,Some(23661587),0,None))), (Some(23661588),Seq(Posting(3,23661743,Some(23661588),0,None), Posting(3,23661682,Some(23661588),0,None))), (Some(23661589),Seq(Posting(4,23661843,Some(23661589),0,None), Posting(4,23661882,Some(23661589),0,None)))) def main(args: Array[String]): Unit = { sc.setLogLevel("ERROR") val rdd = sc.parallelize(data) val rddKeyMax = rdd.map({case(key, v) => val max = v.sortBy(posting => posting.value).last (key, max) }) rddKeyMax.foreach(println) } } /* (Some(23661588),Posting(3,23661743,Some(23661588),0,None)) (Some(23661587),Posting(2,23661682,Some(23661587),0,None)) (Some(23661589),Posting(4,23661882,Some(23661589),0,None)) */ __PRETTY_FUNCTION__和C ++ 17 constexpr constexpr方法创建了一个函数。我还对算法进行了一些更新,以使(感谢@n. 'pronouns' m64387023中的帮助)更加可靠。

std::string_view

在C ++ 20中,可以将函数声明为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__) ,强制其在编译时求值。此外,还有std::basic_fixed_string for use as template parameter

答案 15 :(得分:-2)

以下方法(基于上面的methodName())也可以处理像“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) + "()";
}