Is it possible to print a variable's type in standard C++? -


for example:

int = 12; cout << typeof(a) << endl; 

expected output:

int 

c++11 update old question: print variable type in c++.

the accepted (and good) answer use typeid(a).name(), a variable name.

now in c++11 have decltype(x), can turn expression type. , decltype() comes own set of interesting rules. example decltype(a) , decltype((a)) different types (and , understandable reasons once reasons exposed).

will our trusty typeid(a).name() explore brave new world?

no.

but tool not complicated. , tool using answer question. compare , contrast new tool typeid(a).name(). , new tool built on top of typeid(a).name().

the fundamental issue:

typeid(a).name() 

throws away cv-qualifiers, references, , lvalue/rvalue-ness. example:

const int ci = 0; std::cout << typeid(ci).name() << '\n'; 

for me outputs:

i 

and i'm guessing on msvc outputs:

int 

i.e. const gone. not qoi (quality of implementation) issue. standard mandates behavior.

what i'm recommending below is:

template <typename t> std::string type_name(); 

which used this:

const int ci = 0; std::cout << type_name<decltype(ci)>() << '\n'; 

and me outputs:

int const 

<disclaimer> have not tested on msvc. </disclaimer> welcome feedback do.

the c++11 solution

i using __cxa_demangle non-msvc platforms recommend ipapadop in answer demangle types. on msvc i'm trusting typeid demangle names (untested). , core wrapped around simple testing detects, restores , reports cv-qualifiers , references input type.

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

the results

with solution can this:

int& foo_lref(); int&& foo_rref(); int foo_value();  int main() {     int = 0;     const int ci = 0;     std::cout << "decltype(i) " << type_name<decltype(i)>() << '\n';     std::cout << "decltype((i)) " << type_name<decltype((i))>() << '\n';     std::cout << "decltype(ci) " << type_name<decltype(ci)>() << '\n';     std::cout << "decltype((ci)) " << type_name<decltype((ci))>() << '\n';     std::cout << "decltype(static_cast<int&>(i)) " << type_name<decltype(static_cast<int&>(i))>() << '\n';     std::cout << "decltype(static_cast<int&&>(i)) " << type_name<decltype(static_cast<int&&>(i))>() << '\n';     std::cout << "decltype(static_cast<int>(i)) " << type_name<decltype(static_cast<int>(i))>() << '\n';     std::cout << "decltype(foo_lref()) " << type_name<decltype(foo_lref())>() << '\n';     std::cout << "decltype(foo_rref()) " << type_name<decltype(foo_rref())>() << '\n';     std::cout << "decltype(foo_value()) " << type_name<decltype(foo_value())>() << '\n'; } 

and output is:

decltype(i) int decltype((i)) int& decltype(ci) int const decltype((ci)) int const& decltype(static_cast<int&>(i)) int& decltype(static_cast<int&&>(i)) int&& decltype(static_cast<int>(i)) int decltype(foo_lref()) int& decltype(foo_rref()) int&& decltype(foo_value()) int 

note (for example) difference between decltype(i) , decltype((i)). former type of declaration of i. latter "type" of expression i. (expressions never have reference type, convention decltype represents lvalue expressions lvalue references).

thus tool excellent vehicle learn decltype, in addition exploring , debugging own code.

in contrast, if build on typeid(a).name(), without adding lost cv-qualifiers or references, output be:

decltype(i) int decltype((i)) int decltype(ci) int decltype((ci)) int decltype(static_cast<int&>(i)) int decltype(static_cast<int&&>(i)) int decltype(static_cast<int>(i)) int decltype(foo_lref()) int decltype(foo_rref()) int decltype(foo_value()) int 

i.e. every reference , cv-qualifier stripped off.

c++14 update

just when think you've got solution problem nailed, comes out of , shows better way. :-)

this answer jamboree shows how type name in c++14 @ compile time. brilliant solution couple reasons:

  1. it's @ compile time!
  2. you compiler job instead of library (even std::lib). means more accurate results latest language features (like lambdas).

jamboree's answer doesn't quite lay out vs, , i'm tweaking code little bit. since answer gets lot of views, take time go on there , upvote answer, without which, update never have happened.

#include <cstddef> #include <stdexcept> #include <cstring> #include <ostream>  #ifndef _msc_ver #  if __cplusplus < 201103 #    define constexpr11_tn #    define constexpr14_tn #    define noexcept_tn #  elif __cplusplus < 201402 #    define constexpr11_tn constexpr #    define constexpr14_tn #    define noexcept_tn noexcept #  else #    define constexpr11_tn constexpr #    define constexpr14_tn constexpr #    define noexcept_tn noexcept #  endif #else  // _msc_ver #  if _msc_ver < 1900 #    define constexpr11_tn #    define constexpr14_tn #    define noexcept_tn #  elif _msc_ver < 2000 #    define constexpr11_tn constexpr #    define constexpr14_tn #    define noexcept_tn noexcept #  else #    define constexpr11_tn constexpr #    define constexpr14_tn constexpr #    define noexcept_tn noexcept #  endif #endif  // _msc_ver  class static_string {     const char* const p_;     const std::size_t sz_;  public:     typedef const char* const_iterator;      template <std::size_t n>     constexpr11_tn static_string(const char(&a)[n]) noexcept_tn         : p_(a)         , sz_(n-1)         {}      constexpr11_tn static_string(const char* p, std::size_t n) noexcept_tn         : p_(p)         , sz_(n)         {}      constexpr11_tn const char* data() const noexcept_tn {return p_;}     constexpr11_tn std::size_t size() const noexcept_tn {return sz_;}      constexpr11_tn const_iterator begin() const noexcept_tn {return p_;}     constexpr11_tn const_iterator end()   const noexcept_tn {return p_ + sz_;}      constexpr11_tn char operator[](std::size_t n) const     {         return n < sz_ ? p_[n] : throw std::out_of_range("static_string");     } };  inline std::ostream& operator<<(std::ostream& os, static_string const& s) {     return os.write(s.data(), s.size()); }  template <class t> constexpr14_tn static_string type_name() { #ifdef __clang__     static_string p = __pretty_function__;     return static_string(p.data() + 31, p.size() - 31 - 1); #elif defined(__gnuc__)     static_string p = __pretty_function__; #  if __cplusplus < 201402     return static_string(p.data() + 36, p.size() - 36 - 1); #  else     return static_string(p.data() + 46, p.size() - 46 - 1); #  endif #elif defined(_msc_ver)     static_string p = __funcsig__;     return static_string(p.data() + 38, p.size() - 38 - 7); #endif } 

this code auto-backoff on constexpr if you're still stuck in ancient c++11. , if you're painting on cave wall c++98/03, noexcept sacrificed well.

c++17 update

in comments below lyberta points out new std::string_view can replace static_string:

template <class t> constexpr std::string_view type_name() {     using namespace std; #ifdef __clang__     string_view p = __pretty_function__;     return string_view(p.data() + 34, p.size() - 34 - 1); #elif defined(__gnuc__)     string_view p = __pretty_function__; #  if __cplusplus < 201402     return string_view(p.data() + 36, p.size() - 36 - 1); #  else     return string_view(p.data() + 49, p.find(';', 49) - 49); #  endif #elif defined(_msc_ver)     string_view p = __funcsig__;     return string_view(p.data() + 84, p.size() - 84 - 7); #endif } 

i've updated constants vs nice detective work jive dadson in comments below.


Comments

Popular posts from this blog

c++ - How do I get a multi line tooltip in MFC -

asp.net - In javascript how to find the height and width -

c# - DataTable to EnumerableRowCollection -