সি ++ এ কি একটি __CLASS__ ম্যাক্রো আছে?


102

__CLASS__সি ++ তে কোনও ম্যাক্রো রয়েছে যা ক্লাসের নামটি __FUNCTION__ম্যাক্রোর অনুরূপ দেয় যা ফাংশনটির নাম দেয়

উত্তর:


68

নিকটতম জিনিসটি কল করতে হবে typeid(your_class).name()- তবে এটি সংকলক নির্দিষ্ট ম্যাংলেড নাম তৈরি করে।

ক্লাসের ভিতরে এটি ব্যবহার করার জন্য typeid(*this).name()


4
টাইপড (* এটি) .নেম () শ্রেণি ফাংশনের অভ্যন্তরে ব্যবহার করা যেতে পারে
আলেক্সি পোটভ

4
এটা ভাল. শ্রেণীর জ্ঞান হিসাবে, চর অ্যারে সংজ্ঞায়িত করা রানটাইম পর্যন্ত স্থগিত করার চেয়ে ভাল লাগে।
মাইকেল ক্রেলিন - হ্যাকার

4
এটি একটি করুণ বিষয় যা এটি __ CLASS __ এর মতো সংজ্ঞায়িত হয়নি, এটি প্রিপ্রসেসর পর্যায়ে কার্যকর হতে পারে! :(
কে

4
@ ম্যাক্স এটি না কিন্তু পারে। একইভাবে এটি ফাংশন সম্পর্কে জানে :
পি

4
@ কক্সিক: প্রিপ্রসেসর ফাংশন সম্পর্কে জানেন না, স্ট্যান্ডার্ড __func__এবং অ-স্ট্যান্ডার্ড __FUNCTION__ম্যাক্রো নয়। মাইক্রোসফ্ট __FUNCTION__ম্যাক্রো হিসাবে নথি , কিন্তু এটি যে সত্যিই নয় তা হ'ল এটি যখন আপনি সংকলন করেন তখন এটি প্রিপ্রোসেসর দ্বারা প্রসারিত হয় না /P
স্টিভ জেসপ

77

ব্যবহারের typeid(*this).name()ক্ষেত্রে সমস্যাটি হ'ল thisস্থির পদ্ধতি কলটিতে কোনও পয়েন্টার নেই । ম্যাক্রো__PRETTY_FUNCTION__ স্ট্যাটিক ফাংশনগুলির পাশাপাশি মেথড কলগুলির ক্ষেত্রে একটি শ্রেণির নাম রিপোর্ট করে। তবে এটি কেবল জিসিসি দিয়ে কাজ করবে।

এখানে ম্যাক্রো স্টাইল ইন্টারফেসের মাধ্যমে তথ্য আহরণের উদাহরণ।

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

4
আপনি কি এটি ঘিরে না #ifdef __GNU_C__?
einpoklum

4
এর পরিবর্তে একটি অতিরিক্ত স্ট্রিং তৈরি করতে ছাড়তে substr(0,colons).rfind(" ")ব্যবহার করতে পারে rfind(' ', colons)
মারিউস

4
আমি বরং____ ("::") সন্ধান করব নাহলে অন্যথায় যদি ফাংশনটি থাকে তবে কেবল একটি নামস্থান ফিরে আসবে
22

আমি __METHOD_NAME__ম্যাক্রোর একটি সম্ভবত বিস্তৃত স্কোপ সংস্করণ লিখেছি । এখানে চেক করুন
আন্তোনিও

সি ++ 11 এ আপনি constexprএটি সংকলন সময়ে মূল্যায়নের জন্য এটি একটি ফাংশন করার চেষ্টা করতে পারেন
আন্দ্রে হল্জনার

11

আমি স্কট মেয়ারের "কার্যকর আধুনিক সি ++" থেকে শিখেছি: টাইপইন্ডেক্সকে উত্সাহিত করতে চাই: টাইপইন্ডেক্স , এখানে একটি মৌলিক উদাহরণ রয়েছে:

উদাহরণ

#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


এটির সাথে নামস্থান ছাড়াই কেবল শ্রেণির নাম পাওয়া সম্ভব? ওরফে coliru.stacked-crooked.com/a/cf1b1a865bb7ecc7
টাওয়ার120


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

আপনি যদি এমএস সি ++ (যদি আপনার __FUNCTION__স্ট্যান্ডার্ড হিসাবে বলা উচিত, যেমন একটি অ-মানক এক্সটেনশান হিসাবে কথা বলা হয়) কথা বলছেন তবে এমন কিছু চিহ্ন __FUNCDNAME__এবং __FUNCSIG__চিহ্ন রয়েছে যা আপনি পার্স করতে পারেন


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

আমি ভিজ্যুয়াল সি ++ 12 এর জন্য কাজ করি।


1

__FUNCTION__ম্যাক্রো এবং সি ++ টেম্পলেটগুলির উপর ভিত্তি করে এখানে একটি সমাধান রয়েছে :

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

এমএসভিসি এবং জিসিসি দিয়েও কাজ করে

#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) রয়েছে । "("ডিলিমিটার এবং আরও অনেক কিছুতে আপনি একই ধরণের কেসগুলি সন্ধান করতে পারেন । আমি খুঁজে পাওয়া একমাত্র সমাধানটি প্যারামিটার হিসাবে __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

0

আমি সি ++ 17 পদ্ধতি ব্যবহার করে __PRETTY_FUNCTION__এবং একটি ফাংশন তৈরি করেছি । আমিও অ্যালগরিদম একটি বিট আরো নির্ভরযোগ্যভাবে হতে আপডেট করা (ধন্যবাদ @n 'সর্বনাম' মি। আপনার সাহায্যের জন্য 64387023 )।constexprconstexpr std::string_view

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

সি ++ ২০-এ, কেউ এই ফাংশনটি constevalসংকলন-সময়ে মূল্যায়নের জন্য বাধ্য হিসাবে ঘোষণা করতে পারে । তদ্ব্যতীত, std::basic_fixed_stringটেমপ্লেট প্যারামিটার হিসাবে ব্যবহারের জন্য রয়েছে


-2

নিম্নলিখিত পদ্ধতি (উপরের মেথডনেম () এর উপর ভিত্তি করে) "ইন মেইন (ইন্ট আরজিসি, চর ** আরজিভি)" এর মতো ইনপুটও পরিচালনা করতে পারে:

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.