如何将std::string修改为std::string



我一直在使用一些代码来帮助一些调试,而不必编写数千行动态强制转换或实现返回类名的虚函数。

template <class CLASS>
std::string getClassName(CLASS &theObject)
{
    int status = 0;
    // Convert real name to readable string
    char *realName = abi::__cxa_demangle(typeid(theObject).name(), nullptr,
                                         nullptr, &status);
    ASSERT(status == 0); // Assert for success
    VERIFY(realName, return std::string());
    // Return as string + prevent memory leaks!
    const std::string result(realName);
    free(realName);
    return result;
}

这段代码的思想很简单,输出我们实际使用的类。虽然在切换到Ubuntu 14.04之后,我不再能够使用clang和c++-11/c++-14标准进行编译,所以我已经切换到使用libc++而不是libstdc++。

切换到libc++后,我注意到当我demangle 'std::string'时,它不再输出'std::string',尽管它输出的是:

std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >
当然这是正确的,因为std::string是std::basic_string的类型定义。虽然据我所知,在libc++和libstdc++中,这个定义的方式是相同的,使用了typedef。所以我真的不明白为什么切换到libc++会改变这个要求。

有人知道为什么这是不同的,如何得到'std::string'如果类将是'std::string',和'myTemplate'当类将是'myTemplate'?

提前通知!

JVApen

libc++使用inline namespaces对其ABI进行版本化。它当前使用的内联名称空间是std::__1。这样做是为了让苹果可以同时发布gcc libstdc++和libc++。Dylib A可能链接到libstdc++,而Dylib B可能链接到libc++,应用程序可能链接到两个Dylib。当这种情况发生时,您不希望意外地将libstdc++ std::string与libstdc++ std::string混淆。

它们具有相同的API,因此很容易通过跨dylib边界传递std::string而意外地做到这一点。解决方案是告诉编译器以不同的方式处理它们,这正是内联名称空间所做的(也是发明它的目的)。现在,如果它们在应用程序中意外地混合在一起,就会导致链接时间错误,因为链接器看到的是两种不同的类型,这可以从它们不同的混乱名称中得到证明。

要求者的工作只是简单地告诉你真相:你输入的符号的要求名称是什么。

确实存在一种方法可以在libc++中关闭ABI版本控制。搜索& lt; __config>_LIBCPP_BEGIN_NAMESPACE_STD_LIBCPP_END_NAMESPACE_STD。您可以看到一些平台如何定义它来打开内联命名空间,而另一些则没有。这是一把非常大的锤子,可以用来解决你的问题。如果以这种方式更改libc++的ABI,那么在您的平台上编译和链接针对libc++的所有都必须重新构建。

对于你的问题,我有时会用一个更简单的部分解决方案:

#include <iostream>
#include <type_traits>
#include <memory>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cxxabi.h>
namespace
{
inline
void
filter(std::string& r, const char* b)
{
    const char* e = b;
    for (; *e; ++e)
        ;
    const char* pb = "std::__1::";
    const int pl = std::strlen(pb);
    const char* pe = pb + pl;
    while (true)
    {
        const char* x = std::search(b, e, pb, pe);
        r.append(b, x);
        if (x == e)
            break;
        r += "std::";
        b = x + pl;
    }
}
}  // unnamed namespace
template <typename T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::unique_ptr<char, void(*)(void*)> own
           (
                __cxxabiv1::__cxa_demangle(typeid(TR).name(), nullptr,
                                           nullptr, nullptr),
                std::free
           );
    std::string r;
    if (own)
    {
        if (std::is_const<TR>::value)
            r += "const ";
        if (std::is_volatile<TR>::value)
            r += "volatile ";
        filter(r, own.get());
        if (std::is_lvalue_reference<T>::value)
            r += "&";
        else if (std::is_rvalue_reference<T>::value)
            r += "&&";
    }
    else
        r = typeid(TR).name();
    return r;
}

这只是在呈现给您之前过滤掉混乱名称中的::__1。如果您愿意,您也可以使用相同的技术将std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >转换为std::string

Itanium ABI只有少数几个"压缩"。对应于这样的类型定义。std::stringstd::istreamstd::ostreamstd::iostream

最新更新