C ++에 __CLASS__ 매크로가 있습니까?


100

함수 이름을 제공하는 매크로 __CLASS__와 유사한 클래스 이름을 제공하는 C ++에 매크로 가 있습니까?__FUNCTION__

답변:


67

가장 가까운 것은 호출하는 것입니다 typeid(your_class).name(). 그러나 이것은 컴파일러 특정 이름을 엉망으로 만듭니다.

수업 내에서 사용하려면 typeid(*this).name()


2
typeid (* this) .name ()은 클래스 함수 내에서 사용될 수 있습니다
Aleksei Potov

2
그게 낫다. 클래스를 아는 것에 관해서는 char 배열을 정의하는 것이 런타임까지 연기하는 것보다 낫습니다.
Michael Krelin-해커

5
__ CLASS __처럼 정의되지 않은 것이 유감입니다. 전 처리기 단계에서 편리 할 수 ​​있습니다! :(
k3a 2010-08-23

2
@Max는 아니지만 할 수 있습니다. 비슷한 방식으로 함수에 대해 알고 있습니다.
-P

5
@kexik : 전처리 기는 함수에 대해서도 알지 못합니다. 표준 __func__및 비표준 __FUNCTION__은 매크로가 아닙니다. Microsoft 문서 __FUNCTION__를 매크로로 사용하지만 실제로는 그렇지 않다는 점은 .NET 으로 컴파일 할 때 전처리기에 의해 확장되지 않는다는 것입니다 /P.
Steve Jessop 2011 년

77

사용시 문제 는 정적 메서드 호출에 포인터 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__)

5
이것을 둘러싸 야하지 #ifdef __GNU_C__않습니까?
einpoklum 2014 년

1
대신 여분의 문자열을 생성 substr(0,colons).rfind(" ")하는 rfind(' ', colons)데 사용할 수 있습니다 .
mariusm

1
차라리 find_last_of ( "::") 사용하고 싶지 않습니다. 그렇지 않으면 함수는 네임 스페이스가있는 경우에만 반환합니다
underdoeg

더 넓은 범위의 __METHOD_NAME__매크로 버전을 작성했습니다 . 여기에서 확인 하십시오 .
Antonio

C ++ 11에서는 constexpr컴파일 타임에 이것을 평가 하는 함수 로 만들 수 있습니다
Andre Holzner

11

나는 Scott Meyer의 "Effective Modern C ++"에서 배운 boost :: typeindex 를 제안 하고 싶습니다. 다음은 기본적인 예입니다.

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

"g ++ --std = c ++ 14"로 컴파일하면 다음이 생성됩니다.

산출

템플릿 유형을 인쇄하려면 간단합니다.

T = 이중

객체 인스턴스에서 가져 오려면 decltype을 사용하십시오.

fb의 유형 : foo_bar


이것으로 네임 스페이스없이 클래스 이름 만 얻을 수 있습니까? aka coliru.stacked-crooked.com/a/cf1b1a865bb7ecc7
tower120

10

아직. ( __class__어딘가에서 제안 되었다고 생각합니다 ). 에서 클래스 부분을 추출 할 수도 있습니다 __PRETTY_FUNCTION__.


7

나는 사용할 수 있을 때까지 __PRETTY_FUNCTION__네임 스페이스도 포함하지만 사용하면 충분 하다고 생각 합니다.namespace::classname::functionname__CLASS__


4

컴파일러가 발생 하고 클래스를 포함하여 현재 메서드 이름을 얻는 방법을 원 g++하기 __CLASS__때문에 요청하는 __PRETTY_FUNCTION__경우 도움이 될 것입니다 ( info gcc섹션 5.43 Function Names as Strings에 따라 ).


3

컴파일 타임에 실제로 클래스 이름을 생성 할 무언가가 필요한 경우 C ++ 11을 사용하여 다음을 수행 할 수 있습니다.

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

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

나는 이것이 같은 것이 아니라는 __FUNCTION__것을 알고 있지만 이와 같은 대답을 찾는 동안이 게시물을 찾았습니다. :디



2

클래스 이름을 포함한 함수 이름을 얻을 수 있습니다. 이것은 C 형 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) + "()";
}

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에서 일합니다.


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

포인터-베이스 (아마 괜찮을 것 같음)가있는 경우 이것은 다형성을 고려하지 않습니다.
궤도에서 가벼운 경주

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

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

0

에 의존하는 위에 게시 된 모든 솔루션 __PRETTY_FUNCTION__에는 클래스 이름 / 클래스 이름 만 반환하지 않는 특정 엣지 케이스가 있습니다. 예를 들어 다음과 같은 예쁜 함수 값을 고려하십시오.

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

"::"함수 매개 변수에도 "::"( std::string) 가 포함되어 있으므로 마지막 항목을 delimter로 사용하면 작동하지 않습니다 . "("구분 기호 등의 유사한 경우를 찾을 수 있습니다 . 내가 찾은 유일한 솔루션은 __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

-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) + "()";
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.