Получить имя функции С++ во время компиляции (или время выполнения)
У меня есть метод класса функций, ValueHolder:: printValue
class ValueHolder {
public:
void printValue ();
} ;
Как определить свое искаженное имя во время компиляции (или время выполнения).
Например, я хотел бы сделать это:
const char *mangled_name = GetMangledNameOfSymbol(&ValueHolder::printValue);
Эта функция может возвращать строку, например:
"_ZN11ValueHolder10printValueEv"
В соответствии с @Marco A. Предпосылкой является современный компилятор. Один, который поддерживает typeid, и с включенными флагами, чтобы включить эту функцию.
Я также соглашусь с ответом, который может практиковаться для Gcc и Clang, и заглушкой для MSVC.
Ответы
Ответ 1
Нет стандартного способа сделать это, согласно [lib.type.info]
Класс type_info описывает информацию о типе, сгенерированную реализацией. Объекты этого класса эффективно сохраняют указатель на имя для типа и закодированное значение, подходящее для сравнения двух типов для равенства или порядка сортировки. Имена, правило кодирования и последовательность сортировки для типов не определены и могут различаться между программами.
а для реализации вашего компилятора вы можете использовать typeid(type/expression).name()
, но нигде не указано или не соблюдается, что это имя будет оформлено (оно определено реализацией). Это также зависит от используемых флагов компиляции (спасибо malat).
Пример:
class ValueHolder {
public:
void printValue();
};
int main() {
std::cout << typeid(&ValueHolder::printValue).name();
}
gcc7.0
M11ValueHolderFvvE
clang4.0
M11ValueHolderFvvE
MSVC14
void (__cdecl ValueHolder:: *) (void) __ptr64
Ответ 2
Я добавлю ответ, но я не буду отмечать его правильно. Это не полно. Слишком большой, чтобы добавить в качестве комментария. Это то, что я могу сделать, но я ищу лучший способ. И, да, очень липкий-хриплый. Но я считаю, что есть какой-то API, который, хотя все еще будет немного грубым, будет гарантированно работать (если использовать один компилятор во всем проекте).
template<typename R, typename C, typename... A>
struct MemberFunctionPointer
{
typedef R Return;
typedef C Class;
};
template<typename R, typename C, typename... A>
constexpr auto inferMemberFunctionPointer(R (C::*method)(A...))
{
return MemberFunctionPointer<R,C,A...>{};
}
template<typename M, M m, typename... A>
class GenerateMethodSignature
{
typedef typename decltype(inferMemberFunctionPointer(m))::Class T;
typedef typename decltype(inferMemberFunctionPointer(m))::Return R;
public:
static const char *mangledName (const char *fs)
{
const char *ts = typeid(T).name();
const char *rs = typeid(R).name();
const char *ms = typeid(M).name();
std::string r = "_Z";
if (ts[0] != 'N')
r += "N";
r += ts;
if (ts[0] == 'N')
r.pop_back();
r += std::to_string(strlen(fs));
r += fs;
r += "E";
r += ms + strlen ("M") + strlen(ts) + strlen ("F") + strlen(rs);
r.pop_back();
printf("calculated signature %s\n", r.c_str());
// this is very bad but... for demonstration purposes
return strdup(r.c_str());
}
} ;
namespace MyNamespace {
namespace MySubNamespace {
class MyClass
{
public:
int MyFunction (int myarg);
} ;
} // namespace
} // namespace
#define ExportSignature(T, M) GenerateMethodSignature<decltype(&T::M), &T::M>::mangledName(#M)
const char *myMethodSignature = ExportSignature(MyNamespace::MySubNamespace::MyClass, MyFunction);
Ответ 3
Хорошо, что вы можете сделать, это скомпилировать вашу С++-программу с помощью g++ и получить файл .o. Запустите команду "nm" в файле .o, полученном таким образом, чтобы получить искаженные имена! Этот метод является жизнеспособным в системах Linux.