如何获取C++中变量/表达式的类型
主要有三种方式:
- 使用 C++ 库自带的 typeid 函数;
- 使用 boost 库中 type_id_with_cvr 函数(末尾的 cvr 代表const, variable, reference);
- 自定义模板函数 type_name();
方式一:
typeid 会把获取到的类型信息保存到一个 type_info 类型的对象里面,并返回该对象的常引用;当需要具体的类型信息时,可以通过成员函数来提取。
不像 Java、C# 等动态性较强的语言,C++ 能获取到的类型信息非常有限,也没有统一的标准,如同“鸡肋”一般,大部分情况下我们只是使用重载过的“==”运算符来判断两个类型是否相同。
#include <typeinfo> #include <iostream> int main() { int a = 100; const int b = 101; int& lref = a; int&& rref = std::move(a); std::cout << "int a: type is " << typeid(a).name() << std::endl; std::cout << "const int b: type is " << typeid(b).name() << std::endl; std::cout << "int& lref: type is " << typeid(lref).name() << std::endl; std::cout << "int&& rref: type is " << typeid(rref).name() << std::endl; return 0; }
可以发现:使用 typeid() 打印出来的类型不直观,并且它不支持引用类型的变量,也不能区分const变量。
方式二:
使用 boost 库中 type_id_with_cvr 函数(末尾的cvr代表const, variable, reference),这个方法打印出来的结果就比较优雅了(准确)
但需要下载 Boost 库,并编译安装,才能使用。
#include <iostream> #include <boost/type_index.hpp> int main() { int a = 100; const int b = 101; int& lref = a; int&& rref = std::move(a); std::cout << "int a: type is " << boost::typeindex::type_id_with_cvr<decltype(a)>().pretty_name() << std::endl; std::cout << "const int b: type is " << boost::typeindex::type_id_with_cvr<decltype(b)>().pretty_name() << std::endl; std::cout << "int& lref: type is " << boost::typeindex::type_id_with_cvr<decltype(lref)>().pretty_name() << std::endl; std::cout << "int&& rref: type is " << boost::typeindex::type_id_with_cvr<decltype(rref)>().pretty_name() << std::endl; return 0; }
输出结果:
int a: type is int const int b: type is int const int& lref: type is int& int&& rref: type is int&&
方式二:
定义了一个模板函数 type_name(),可以对传入的模板类型 T 进行类型判断,结合指针、左值/右值引用、常类型,准确得出变量的类型。在调用该函数时使用了decltype
关键字,传入待确定的变量,然后输出变量类型。
#include <type_traits> #include <typeinfo> #include <memory> #include <string> #include <cstdlib> #include <iostream> #ifndef _MSC_VER #include <cxxabi.h> #endif using namespace std; template <class T> string type_name() { typedef typename remove_reference<T>::type TR; unique_ptr<char, void (*)(void *)> own( #ifndef _MSC_VER abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr), #else nullptr, #endif free); string r = own != nullptr ? own.get() : typeid(TR).name(); if (is_const<TR>::value) r += " const"; if (is_volatile<TR>::value) r += " volatile"; if (is_lvalue_reference<T>::value) r += "&"; else if (is_rvalue_reference<T>::value) r += "&&"; return r; } int main() {
int a = 100;
const int b = 101;
int& lref = a;
int&& rref = std::move(a);
cout << "int a: type is " << type_name<decltype(a)>() << endl;
cout << "const int b: type is " << type_name<decltype(b)>() << endl;
cout << "int& lref: type is " << type_name<decltype(lref)>() << endl;
cout << "int&& rref: type is " << type_name<decltype(rref)>() << endl;
}
结果如下: