Как развязать искаженные имена С++ lambdas?

После компиляции с g++-4.9.3 -std=c++11 код

#include <iostream>
#include <typeinfo>
using namespace std;
int main() { cout << typeid([]{}).name() << endl; }

выводит Z4mainEUlvE_ как искаженное имя данной лямбды на Linux x86_64. Однако инструмент c++filt не может его развернуть. Он просто выводит введенный ему ввод, Z4mainEUlvE_.

Как мне его развернуть?

Ответы

Ответ 1

Вы можете использовать специальную функцию abi::__cxa_demangle GCC:

#include <memory>
#include <cstdlib>
#include <cxxabi.h>
#include <iostream>

// delete malloc'd memory
struct malloc_deleter
{
    void operator()(void* p) const { std::free(p); }
};

// custom smart pointer for c-style strings allocated with std::malloc
using cstring_uptr = std::unique_ptr<char, malloc_deleter>;

int main()
{
    // special function to de-mangle names
    int error;
    cstring_uptr name(abi::__cxa_demangle(typeid([]{}).name(), 0, 0, &error));

    if(!error)
        std::cout << name.get() << '\n';
    else if(error == -1)
        std::cerr << "memory allocation failed" << '\n';
    else if(error == -2)
        std::cerr << "not a valid mangled name" << '\n';
    else if(error == -3)
        std::cerr << "bad argument" << '\n';
}

Вывод:

main::{lambda()#1}

В соответствии с Документация эта функция возвращает строку с нулевым символом c-style, выделенную с помощью std:: malloc, который вызывающий должен освободить, используя std:: free. В этом примере используется интеллектуальный указатель, чтобы автоматически освободить возвращаемую строку в конце области.

Ответ 2

Использование c++filt version 070207 20070207:

$ c++filt -n Z4mainEUlvE_
main::'lambda'()

Хотя, как отмечали комментаторы, эти имена не всегда полностью полезны.

Ответ 3

Если вам не нужно это внутри вашего кода и его только для удовольствия, используйте онлайн-инструмент, например http://d.fuqu.jp/c++filtjs/, который для Z4mainEUlvE_ возвращает main::{lambda()#1}.

Другие инструменты можно найти в разделе этот вопрос о переполнении стека.

Ответ 4

Вы можете попробовать использовать boost::core::demangle, но я не знаю, будут ли ваши результаты другими.

Например

#include <boost/core/demangle.hpp>
#include <iostream>

int main () {
  std::cout  << boost::core::demangle (typeid ([](){}).name ()) << std::endl;
}