次のおもちゃの例では、関数の名前を取得したいと思います。関数自体がstd::function
引数として渡されました。 C++ではstd::function
オブジェクトの名前を取得できますか?
void printName(std::function<void()> func){
//Need a function name()
std::cout << func.name();
}
void magic(){};
//somewhere in the code
printName(magic());
output: magic
そうでなければ、関数の名前を2番目のパラメーターとして指定する必要があります。
いいえ、ありません。関数名(変数名など)はコンパイルされ、実行時に表示されません。
あなたの最善の策は、関数の名前を渡すことです(std::string
またはconst char*
)あなたが提案したとおり。 (あるいは、あなたcould__func__
はC++ 11で導入されました。)
答えはノーですが、あなたは次のようなものを作ることができます
template<class R, class... Args>
class NamedFunction
{
public:
std::string name;
std::function<R(Args...)> func;
NamedFunction(std::string pname, std::function<R(Args...)> pfunc) : name(pname), func(pfunc)
{}
R operator()(Args&&... a)
{
return func(std::forward<Args>(a)...);
}
};
そして、プリプロセッサを定義します
#define NAMED_FUNCTION(var, type, x) NamedFunction<type> var(#x,x)
...
NAMED_FUNCTION(f, void(), magic);
std::function
を指定すると、格納されている関数オブジェクトのtypeid
を返すtarget_type
というメンバー関数があります。それはあなたができることを意味します
void printName(std::function<void()> func){
//Need a function name()
std::cout << func.target_type().name();
}
これは、各タイプに固有の実装定義の文字列を返します。 Visual Studioでは、この文字列はすでに人間が読める形式になっています。 gcc(または多分それはglibcですか?だれが詳細に処理するのかわかりません)では、abi::__cxa_demangle
をインクルードした後に<cxxabi.h>
を使用して、人間が読めるバージョンの型名を取得する必要があります。
[〜#〜]編集[〜#〜]
Matthieu M.が指摘したように、関数ポインタが与えられた場合、これによって返される型は関数のシグネチャになります。例えば:
int function(){return 0;}
printName(function);
これは(必要に応じて解体されたと想定して)int (*)()
を出力しますが、これは関数名ではありません。
ただし、このメソッドはクラスで機能します。
struct Function
{
int operator()(){return 0;}
};
printName(Function{});
これは、必要に応じてFunction
を出力しますが、関数ポインターでは機能しません。
名前の文字列パラメータを関数に設定し、マクロを使用してそれを呼び出すこともできます
void _printName(std::function<void()> func, const std::string& funcName){
std::cout << funcName;
}
#define printName(f) _printName(f, #f)
void magic(){};
//somewhere in the code
printName(magic);
関数ポインタから名前への独自のマップを維持します。
_template<class Sig>
std::map<Sig*, const char*>& name_map() {
static std::map<Sig*, const char*> r;
return r;
}
struct register_name_t {
template<class Sig>
register_name_t( Sig* sig, const char* name ) {
name_map()[sig]=name;
}
};
#define TO_STRING(A) #A
#define REGISTER_NAME(FUNC) \
register_name_t FUNC ## _register_helper_() { \
static register_name_t _{ FUNC, TO_STRING(FUNC) }; \
return _; \
} \
static auto FUNC ## _registered_ = FUNC ## _register_helper_()
_
名前magic
を関数magic
に登録するには、単にREGISTER_NAME(magic);
を実行します。これは、ヘッダーまたはcppファイルのいずれかのファイルスコープで行う必要があります。
次に、_std::function
_に、その内部に格納されているシグネチャと一致する関数ポインターがあるかどうかを確認します。その場合は、_name_map
_で調べ、見つかった場合は名前を返します。
_template<class Sig>
std::string get_function_name( std::function<Sig> const& f ) {
auto* ptr = f.target<Sig*>();
if (!ptr) return {};
auto it = name_map().find(ptr);
if (it == name_map().end()) return {};
return it->second;
}
_
これは一般に悪い考えです。