Template which prints the name of the given type

别来无恙 提交于 2019-12-20 01:39:16

问题


I would like to print the name of a type for debugging purposes, so I've created a function which does the trick (in fact, I borrowed it from another SO answer, which I cannot found now), the function looks like this:

template <typename T> std::string TypeName(T)
{
    auto name = typeid(T).name();
    int status = 0;

    std::unique_ptr<char, void(*)(void*)> res {
        abi::__cxa_demangle(name, NULL, NULL, &status),
        std::free
    };

    return ((status == 0) ? res.get() : name);
}

Live Demo

It works fine:

int i = 0;
float f = 0.f;

std::cout << TypeName(i) << '\n'; // int
std::cout << TypeName(f) << '\n'; // float, so far so good

std::cout << TypeName(&i) << '\n'; // int *
std::cout << TypeName(&f) << '\n'; // float *, as expected

But it lacks of the capacity of dealing with top-level cv-cualifiers and references:

const int ci = 1;
const float cf = 1.f;

std::cout << TypeName(ci) << '\n'; // int! (instead of const int)
std::cout << TypeName(cf) << '\n'; // float! (instead of const float)

int &ri = i;
float &rf = f;

std::cout << TypeName(ri) << '\n'; // int! (instead of int &)
std::cout << TypeName(rf) << '\n'; // float! (instead of float &)

Well, I can't say that this is unexpected, because the function TypeName is a function template and the type T follows the template type deduction but this issue makes the whole thing almost useless.

So, my question is: Is there anything that can be done in order create a template function (which can get any type as input) to obtain the type name without loosing the top-level cv-cualifiers and references?

Thanks in advance.


回答1:


The only C++ language construct that can tell the difference between an lvalue that is an id-expression and an lvalue that is a reference is decltype. Here's an example of how to use it, including (ab)use of a macro to keep the same calling pattern you already have:

template <typename T> std::string TypeName() {
    auto name = typeid(T()).name();  // function type, not a constructor call!
    int status = 0;

    std::unique_ptr<char, void(*)(void*)> res {
        abi::__cxa_demangle(name, NULL, NULL, &status),
        std::free
    };

    std::string ret((status == 0) ? res.get() : name);
    if (ret.substr(ret.size() - 3) == " ()") ret.resize(ret.size() - 3);
    return ret;
}
#define TypeName(e) TypeName<decltype(e)>()

Because abi::__cxa_demangle ignores top-level cv and reference qualifiers, we construct a function type and then strip the trailing brackets.

This gives int const, int&, int const& as required.



来源:https://stackoverflow.com/questions/25891266/template-which-prints-the-name-of-the-given-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!