最終更新日時(UTC):
が更新

履歴 編集

事前定義識別子__func__(C++11)

概要

C99互換として、事前定義識別子(predefined identifier)の__func__が導入された。

__func__には、現在いる関数名が文字列として格納されている。この識別子は、関数内でのみ使用できる。

仕様

識別子__func__は、事前定義された関数のローカル変数として定義され、以下のように暗黙に定義される:

static const char __func__[] = "function-name";

"function-name"には、実装定義の文字列が格納される。そのため、マングリングされた関数名、オーバーロード、名前空間、所属するクラスなどの扱いは、実装ごとに異なる可能性がある。多くの場合、__func__には関数の名前のみが格納され、名前空間名、クラス名、戻り値の型やパラメータといった情報は含まれない。

変数__func__が、プログラム内の他の変数と異なるアドレスを持っているかどうかは未規定

備考

GCCは言語拡張として、__FUNCTION__識別子と__PRETTY_FUNCTION__識別子を持つ。__FUNCTION____func__の別名として定義される。__PRETTY_FUNCTION__は、名前空間名、クラス名、戻り値やパラメータといった情報も含む関数の文字列となる。

Visual C++は言語拡張として、__FUNCTION__識別子、__FUNCDNAME__識別子、__FUNCSIG__識別子を持つ。__FUNCTION__はスコープやシグニチャの情報を持たない関数名、__FUNCDNAME__はマングリングされた関数名、__FUNCSIG__は戻り値やパラメータといったシグニチャの情報を持つ関数名となる。

#include <iostream>

class S {
  const char* funcname_ = nullptr;
public:
  // コンストラクタでは、初期化子リストの時点から__func__を使用できる
  S()
    : funcname_(__func__) {}

  void print()
  {
    std::cout << "S::S() : " << funcname_ << std::endl;

    // メンバ関数名
    std::cout << "S::print() : " << __func__ << std::endl;
  }
};

void f()
{
  // 関数名
  std::cout << "f() : " << __func__ << std::endl;
}

// void g(const char* s = __func__) {}
// コンパイルエラー : __func__は関数内でのみ使用できる

int main()
{
  // main関数の名前
  std::cout << "main() : " << __func__ << std::endl;

  f();
  S().print();
}

出力例

main() : main
f() : f
S::S() : S
S::print() : print

検討されたほかの選択肢

__func__はクラスや名前空間といったスコープ全体の情報を持たないために、現在のクラス名を取得する__class__、現在の名前空間名を取得する__namespace__も検討された。しかし、これらはアイディアとして挙がったのみで、提案はされなかった。

参照