打印给定类型的名称的模板 [英] Template which prints the name of the given type

查看:106
本文介绍了打印给定类型的名称的模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想打印一个类型的名称为调试目的,所以我创建了一个函数做的伎俩(事实上,我借用它从另一个SO答案,我现在不能找到),函数看像这样:

  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);
}

现场演示



它工作正常:

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

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

std :: cout<< TypeName(& i)<< '\\\
'; // int *
std :: cout<< TypeName(& f)<< '\\\
'; // float *,正如预期的

但它缺少处理顶级流标和参考文献:

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

std :: cout<< TypeName(ci)<< '\\\
'; // int! (而不是const int)
std :: cout<< TypeName(cf)<< '\\\
'; // float! (而不是const float)

int& ri = i;
float& rf = f

std :: cout<< TypeName(ri)<< '\\\
'; // int! (而不是int&)
std :: cout<< TypeName(rf)<< '\\\
'; // float! (而不是float&)

好吧,我不能说这是意想不到的,因为函数 TypeName 是一个函数模板,类型 T 遵循模板类型扣除,但这个问题使整个事情几乎无用。



所以,我的问题是:有没有什么可以做,以创建一个模板函数(可以获得任何类型作为输入)获取类型名称

解决方案



只有 C ++语言结构可以判断为一个 id-expression 的左值和作为引用的左值之间的差异 decltype 。下面是一个如何使用它的例子,包括(ab)使用宏来保持你已经拥有的相同的调用模式:

  template< typename T> std :: string TypeName(){
auto name = typeid(T())。 //函数类型,不是构造函数调用!
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)>()


$ b b

因为 abi :: __ cxa_demangle 忽略顶级cv和引用限定符,我们构造一个函数类型,然后剥去尾括号。



这会给出 int const int& int const& ;


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.

解决方案

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.

这篇关于打印给定类型的名称的模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆