Получить имя функции С++ во время компиляции (или время выполнения)

У меня есть метод класса функций, 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.