C++ is a strongly-typed language. This means that every variable and expression has a type, and that type is known at compile-time. There are many times when we need to know the type of a variable or expression, especially when debugging or dealing with templates.
The C++ standard provides the typeid
operator for this purpose. It gives us the type of an expression in the form of a std::type_info
object, but it might not always give us the type in a human-readable format. For example, for the type int
, it might return i
instead of int
.
To solve this problem, we can use a handy function, type_name()
, which takes a template parameter T
and returns a string containing the human-readable name of T
. The code snippet above presents a definition of this function. Let's break it down:
Understanding the type_name() Function
The function type_name()
is a template function that accepts a type T
and returns its name as a std::string
.
template <class T>
std::string type_name()
{
//...
}
T
using std::remove_reference<T>::type
:typedef typename std::remove_reference<T>::type TR;
TR
using abi::__cxa_demangle
if available. The function then constructs a string r
with the demangled name, or typeid(TR).name()
if demangling is not available. const
, volatile
, and reference symbols (&
or &&
), if they exist:#include <type_traits>
#include <typeinfo>
#ifndef _MSC_VER
# include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>
template <class T>
std::string
type_name()
{
typedef typename std::remove_reference<T>::type TR;
std::unique_ptr<char, void(*)(void*)> own
(
#ifndef _MSC_VER
abi::__cxa_demangle(typeid(TR).name(), nullptr,
nullptr, nullptr),
#else
nullptr,
#endif
std::free
);
std::string r = own != nullptr ? own.get() : typeid(TR).name();
if (std::is_const<TR>::value)
r += " const";
if (std::is_volatile<TR>::value)
r += " volatile";
if (std::is_lvalue_reference<T>::value)
r += "&";
else if (std::is_rvalue_reference<T>::value)
r += "&&";
return r;
};
Using the type_name() Function
The type_name()
function can be used like the following.
In this code, decltype
is used to fetch the type of a variable or expression, and type_name()
is used to print its human-readable name.
Running this code will output:class Widget {public:int x, y;};auto f(){int a = 9;cout << type_name<decltype(a)>() << endl;cout << type_name<decltype((a))>() << endl;return a;}int main(void){Widget w;Widget &rw = w;auto aw = rw;auto daw = rw;cout << type_name<decltype(aw)>() << endl;cout << type_name<decltype(daw)>() << endl;f();return 0;}
Widget
Widget&
int
int&
This output shows the type names of the variables aw
, daw
, a
, and (a)
, respectively.
In conclusion, the type_name()
function is a helpful tool for debugging and understanding C++ type information. It provides a human-readable type name and handles const, volatile, and reference qualifiers. It's a great addition to any C++ developer's toolkit.
No comments:
Post a Comment