C ++ में __CLASS__ मैक्रो है?


100

क्या __CLASS__C ++ में एक मैक्रो है जो क्लास को __FUNCTION__मैक्रो के समान नाम देता है जो फ़ंक्शन का नाम देता है

जवाबों:


67

कॉल करने के लिए निकटतम चीज़ है typeid(your_class).name()- लेकिन यह संकलक विशिष्ट मंगल नाम का उत्पादन करता है।

सिर्फ कक्षा के अंदर इसका उपयोग करने के लिए typeid(*this).name()


2
typeid (* this) .name () को क्लास के फंक्शन्स के अंदर इस्तेमाल किया जा सकता है
अलेक्सी पोटोव

2
वह बेहतर है। कक्षा को जानने के लिए, चार सरणी को परिभाषित करना इसे रनटाइम तक स्थगित करने से बेहतर लगता है।
माइकल क्रेलिन -

5
यह एक दया है कि इसे __ क्लास __ की तरह परिभाषित नहीं किया जाता है, यह प्रीप्रोसेसर स्टेज पर काम कर सकता है! :(
k3a

2
@ मोम यह नहीं है, लेकिन कर सकता है। इसी तरह से यह फ़ंक्शन के बारे में जानता है :-P
k3a

5
@kexik: प्रीप्रोसेसर को फ़ंक्शन के बारे में पता नहीं है, मानक __func__और गैर-मानक __FUNCTION__मैक्रोज़ नहीं हैं। Microsoft __FUNCTION__एक मैक्रो के रूप में दस्तावेज़ करता है, लेकिन सस्ता है कि यह वास्तव में नहीं है, यह है कि जब आप इसका अनुपालन करते हैं तो यह प्रीप्रोसेसर द्वारा विस्तारित नहीं होता है /P
स्टीव जेसप

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__?
ईनपोकलम

1
substr(0,colons).rfind(" ")एक के बजाय rfind(' ', colons)एक अतिरिक्त स्ट्रिंग के निर्माण को रोकने के लिए उपयोग कर सकता है ।
मर्सिडीज

1
मैं इसके बजाय find_last_of ("::") का उपयोग करता हूं अन्यथा अन्यथा फ़ंक्शन केवल एक नेमस्पेस लौटाएगा अगर वहाँ एक है
underdoeg

मैंने __METHOD_NAME__मैक्रो का संभवतः व्यापक दायरा संस्करण लिखा । चेक यहाँ
एंटोनियो

C ++ 11 में आप constexprसंकलन के समय इसका मूल्यांकन करने के लिए इसे एक फंक्शन बनाने की कोशिश कर सकते हैं
आंद्रे होल्जनर

11

मैं बढ़ावा देने का सुझाव देना चाहूंगा :: 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" के साथ संकलित यह निम्नलिखित उत्पादन करता है

उत्पादन

यदि आप टेम्पलेट प्रकार प्रिंट करना चाहते हैं, तो यह आसान है।

टी = डबल

ऑब्जेक्ट उदाहरण से इसे प्राप्त करने के लिए, बस डिक्लेपट का उपयोग करें:

fb का प्रकार है: foo_bar


क्या इस के साथ नाम स्थान के बिना सिर्फ वर्ग नाम प्राप्त करना संभव है? उर्फ कोलीरू.स्टैक्ड- croched.com/a/cf1b1a865bb7ecc7
टॉवर120

10

अभी नहीं। (मुझे लगता __class__है कि कहीं प्रस्तावित है)। आप वर्ग भाग को निकालने का प्रयास भी कर सकते हैं __PRETTY_FUNCTION__


7

मुझे लगता है कि उपयोग __PRETTY_FUNCTION__करना काफी अच्छा है, हालांकि इसमें नाम स्थान भी शामिल है, namespace::classname::functionnameजब तक कि __CLASS__यह उपलब्ध नहीं है।


4

यदि आपका कंपाइलर होता है g++और आप मांग रहे हैं __CLASS__क्योंकि आप क्लास सहित वर्तमान विधि नाम प्राप्त करने का तरीका चाहते हैं, __PRETTY_FUNCTION__तो मदद करनी चाहिए (तदनुसार info gcc, धारा 5.43 फ़ंक्शन नाम स्ट्रिंग्स के रूप में )।


3

यदि आपको कुछ ऐसा चाहिए जो वास्तव में संकलन के समय वर्ग नाम का उत्पादन करेगा, तो आप ऐसा करने के लिए C ++ 11 का उपयोग कर सकते हैं:

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

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

मैं मानता हूं कि यह वैसा नहीं है, __FUNCTION__बल्कि मुझे इस तरह का जवाब ढूंढते हुए यह पोस्ट मिला। : डी



2

आप फ़ंक्शन का नाम क्लास नाम सहित प्राप्त कर सकते हैं। यह सी-प्रकार के कवक को संसाधित कर सकता है।

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

मैं विजुअल 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)

अंतिम "::"पैरामीटर के रूप में परिसीमन काम नहीं करेगा क्योंकि फंक्शन पैरामीटर में a "::"( 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

-2

निम्नलिखित विधि (मेथडनाम (ऊपर) के आधार पर) "इंट मेन (int argc, char ** argc)" जैसे इनपुट को भी हैंडल कर सकती है:

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) + "()";
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.