C ++に__CLASS__マクロはありますか?


100

関数名を与えるマクロに__CLASS__似たクラス名を与えるC ++のマクロはありますか__FUNCTION__

回答:


67

一番近いのは呼び出すことですがtypeid(your_class).name()、これによりコンパイラ固有のマングル名が生成されます。

クラス内で使用するには typeid(*this).name()


2
typeid(* this).name()はクラス関数の内部で使用できます
Aleksei Potov

2
それは良いです。クラスを知ることに関しては、char配列を定義する方が実行時まで延期するよりも良い音がします。
Michael Krelin-ハッカー、2009年

5
__ CLASS __のように定義されていないのは残念ですが、プリプロセッサ段階で便利です!:(
k3a 2010

2
@Maxできませんでした。関数について知る同様の方法:-P
k3a

5
@kexik:プリプロセッサは関数についても認識しません。標準__func__と非標準__FUNCTION__はマクロではありません。Microsoft __FUNCTION__はマクロとして文書化していますが、実際にはそうではないということは、でコンパイルしたときにプリプロセッサによって展開されないことです/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 2014年

1
私はむしろ(「::」)find_last_of使用したい1がある場合、それ以外の機能は専用の名前空間を返します
underdoeg

私は__METHOD_NAME__マクロのより広いスコープのバージョンを書いた。こちらをチェックしてください
アントニオ

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


これで名前空間なしでクラス名だけを取得することは可能ですか?別名coliru.stacked-crooked.com/a/cf1b1a865bb7ecc7
Tower120


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__ような答えを探しているときにこの投稿を見つけました。:D



2

クラス名を含む関数名を取得できます。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) + "()";
}

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)が含まれているため、最後に出現したas 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.