<p>For example:</p>

<pre><code>int a = 12;
cout &lt;&lt; typeof(a) &lt;&lt; endl;
</code></pre>

<p>Expected output:</p>

<pre><code>int
</code></pre>

[{'answer_id': 81886, 'author': 'Konrad Rudolph', 'author_id': 1968, 'author_profile': 'https://Stackoverflow.com/users/1968', 'pm_score': 8, 'selected': False, 'text': '<p>Try:</p>\n\n<pre class="lang-cpp prettyprint-override"><code>#include &lt;typeinfo&gt;\n\n// …\nstd::cout &lt;&lt; typeid(a).name() &lt;&lt; \'\\n\';\n</code></pre>\n\n<p>You might have to activate RTTI in your compiler options for this to work. Additionally, the output of this depends on the compiler. It might be a raw type name or a name mangling symbol or anything in between.</p>\n'}, {'answer_id': 81913, 'author': 'mdec', 'author_id': 15534, 'author_profile': 'https://Stackoverflow.com/users/15534', 'pm_score': 6, 'selected': False, 'text': "<p>Don't forget to include <code>&lt;typeinfo&gt;</code></p>\n\n<p>I believe what you are referring to is runtime type identification. You can achieve the above by doing .</p>\n\n<pre><code>#include &lt;iostream&gt;\n#include &lt;typeinfo&gt;\n\nusing namespace std;\n\nint main() {\n  int i;\n  cout &lt;&lt; typeid(i).name();\n  return 0;\n}\n</code></pre>\n"}, {'answer_id': 81939, 'author': 'Greg Hewgill', 'author_id': 893, 'author_profile': 'https://Stackoverflow.com/users/893', 'pm_score': 4, 'selected': False, 'text': '<p>You could use a traits class for this. Something like:</p>\n\n<pre><code>#include &lt;iostream&gt;\nusing namespace std;\n\ntemplate &lt;typename T&gt; class type_name {\npublic:\n    static const char *name;\n};\n\n#define DECLARE_TYPE_NAME(x) template&lt;&gt; const char *type_name&lt;x&gt;::name = #x;\n#define GET_TYPE_NAME(x) (type_name&lt;typeof(x)&gt;::name)\n\nDECLARE_TYPE_NAME(int);\n\nint main()\n{\n    int a = 12;\n    cout &lt;&lt; GET_TYPE_NAME(a) &lt;&lt; endl;\n}\n</code></pre>\n\n<p>The <code>DECLARE_TYPE_NAME</code> define exists to make your life easier in declaring this traits class for all the types you expect to need.</p>\n\n<p>This might be more useful than the solutions involving <code>typeid</code> because you get to control the output. For example, using <code>typeid</code> for <code>long long</code> on my compiler gives "x".</p>\n'}, {'answer_id': 81956, 'author': 'Nick', 'author_id': 3233, 'author_profile': 'https://Stackoverflow.com/users/3233', 'pm_score': 5, 'selected': False, 'text': '<p>You can use templates.</p>\n\n<pre><code>template &lt;typename T&gt; const char* typeof(T&amp;) { return "unknown"; }    // default\ntemplate&lt;&gt; const char* typeof(int&amp;) { return "int"; }\ntemplate&lt;&gt; const char* typeof(float&amp;) { return "float"; }\n</code></pre>\n\n<p>In the example above, when the type is not matched it will print "unknown". </p>\n'}, {'answer_id': 82102, 'author': 'paercebal', 'author_id': 14089, 'author_profile': 'https://Stackoverflow.com/users/14089', 'pm_score': 5, 'selected': False, 'text': "<p>Note that the names generated by the RTTI feature of C++ is <strong>not</strong> portable.\nFor example, the class</p>\n\n<pre><code>MyNamespace::CMyContainer&lt;int, test_MyNamespace::CMyObject&gt;\n</code></pre>\n\n<p>will have the following names:</p>\n\n<pre><code>// MSVC 2003:\nclass MyNamespace::CMyContainer[int,class test_MyNamespace::CMyObject]\n// G++ 4.2:\nN8MyNamespace8CMyContainerIiN13test_MyNamespace9CMyObjectEEE\n</code></pre>\n\n<p>So you can't use this information for serialization. But still, the typeid(a).name() property can still be used for log/debug purposes</p>\n"}, {'answer_id': 82144, 'author': 'James Hopkin', 'author_id': 11828, 'author_profile': 'https://Stackoverflow.com/users/11828', 'pm_score': 3, 'selected': False, 'text': '<p>The other answers involving RTTI (typeid) are probably what you want, as long as:</p>\n\n<ul>\n<li>you can afford the memory overhead (which can be considerable with some compilers)</li>\n<li>the class names your compiler returns are useful</li>\n</ul>\n\n<p>The alternative, (similar to Greg Hewgill\'s answer), is to build a compile-time table of traits.</p>\n\n<pre><code>template &lt;typename T&gt; struct type_as_string;\n\n// declare your Wibble type (probably with definition of Wibble)\ntemplate &lt;&gt;\nstruct type_as_string&lt;Wibble&gt;\n{\n    static const char* const value = "Wibble";\n};\n</code></pre>\n\n<p>Be aware that if you wrap the declarations in a macro, you\'ll have trouble declaring names for template types taking more than one parameter (e.g. std::map), due to the comma.</p>\n\n<p>To access the name of the type of a variable, all you need is</p>\n\n<pre><code>template &lt;typename T&gt;\nconst char* get_type_as_string(const T&amp;)\n{\n    return type_as_string&lt;T&gt;::value;\n}\n</code></pre>\n'}, {'answer_id': 14617848, 'author': 'NickV', 'author_id': 1617892, 'author_profile': 'https://Stackoverflow.com/users/1617892', 'pm_score': 7, 'selected': False, 'text': '<p>Very ugly but does the trick if you only want compile time info (e.g. for debugging):</p>\n\n<pre><code>auto testVar = std::make_tuple(1, 1.0, "abc");\ndecltype(testVar)::foo= 1;\n</code></pre>\n\n<p>Returns:</p>\n\n<pre><code>Compilation finished with errors:\nsource.cpp: In function \'int main()\':\nsource.cpp:5:19: error: \'foo\' is not a member of \'std::tuple&lt;int, double, const char*&gt;\'\n</code></pre>\n'}, {'answer_id': 14633413, 'author': 'ipapadop', 'author_id': 487362, 'author_profile': 'https://Stackoverflow.com/users/487362', 'pm_score': 5, 'selected': False, 'text': '<p>As mentioned, <code>typeid().name()</code> may return a mangled name. In GCC (and some other compilers) you can work around it with the following code:</p>\n\n<pre><code>#include &lt;cxxabi.h&gt;\n#include &lt;iostream&gt;\n#include &lt;typeinfo&gt;\n#include &lt;cstdlib&gt;\n\nnamespace some_namespace { namespace another_namespace {\n\n  class my_class { };\n\n} }\n\nint main() {\n  typedef some_namespace::another_namespace::my_class my_type;\n  // mangled\n  std::cout &lt;&lt; typeid(my_type).name() &lt;&lt; std::endl;\n\n  // unmangled\n  int status = 0;\n  char* demangled = abi::__cxa_demangle(typeid(my_type).name(), 0, 0, &amp;status);\n\n  switch (status) {\n    case -1: {\n      // could not allocate memory\n      std::cout &lt;&lt; "Could not allocate memory" &lt;&lt; std::endl;\n      return -1;\n    } break;\n    case -2: {\n      // invalid name under the C++ ABI mangling rules\n      std::cout &lt;&lt; "Invalid name" &lt;&lt; std::endl;\n      return -1;\n    } break;\n    case -3: {\n      // invalid argument\n      std::cout &lt;&lt; "Invalid argument to demangle()" &lt;&lt; std::endl;\n      return -1;\n    } break;\n }\n std::cout &lt;&lt; demangled &lt;&lt; std::endl;\n\n free(demangled);\n\n return 0;\n</code></pre>\n\n<p>}</p>\n'}, {'answer_id': 20170989, 'author': 'Howard Hinnant', 'author_id': 576911, 'author_profile': 'https://Stackoverflow.com/users/576911', 'pm_score': 11, 'selected': True, 'text': '<p>C++11 update to a very old question: Print variable type in C++.</p>\n<p>The accepted (and good) answer is to use <code>typeid(a).name()</code>, where <code>a</code> is a variable name.</p>\n<p>Now in C++11 we have <code>decltype(x)</code>, which can turn an expression into a type.  And <code>decltype()</code> comes with its own set of very interesting rules.  For example <code>decltype(a)</code> and <code>decltype((a))</code> will generally be different types (and for good and understandable reasons once those reasons are exposed).</p>\n<p>Will our trusty <code>typeid(a).name()</code> help us explore this brave new world?</p>\n<p>No.</p>\n<p>But the tool that will is not that complicated.  And it is that tool which I am using as an answer to this question.  I will compare and contrast this new tool to <code>typeid(a).name()</code>.  And this new tool is actually built on top of <code>typeid(a).name()</code>.</p>\n<p><strong>The fundamental issue:</strong></p>\n<pre><code>typeid(a).name()\n</code></pre>\n<p>throws away cv-qualifiers, references, and lvalue/rvalue-ness.  For example:</p>\n<pre><code>const int ci = 0;\nstd::cout &lt;&lt; typeid(ci).name() &lt;&lt; \'\\n\';\n</code></pre>\n<p>For me outputs:</p>\n<pre><code>i\n</code></pre>\n<p>and I\'m guessing on MSVC outputs:</p>\n<pre><code>int\n</code></pre>\n<p>I.e. the <code>const</code> is gone.  This is not a QOI (Quality Of Implementation) issue.  The standard mandates this behavior.</p>\n<p>What I\'m recommending below is:</p>\n<pre><code>template &lt;typename T&gt; std::string type_name();\n</code></pre>\n<p>which would be used like this:</p>\n<pre><code>const int ci = 0;\nstd::cout &lt;&lt; type_name&lt;decltype(ci)&gt;() &lt;&lt; \'\\n\';\n</code></pre>\n<p>and for me outputs:</p>\n<pre><code>int const\n</code></pre>\n<p><code>&lt;disclaimer&gt;</code> I have not tested this on MSVC. <code>&lt;/disclaimer&gt;</code>  But I welcome feedback from those who do.</p>\n<p><strong>The C++11 Solution</strong></p>\n<p>I am using <code>__cxa_demangle</code> for non-MSVC platforms as recommend by <a href="https://stackoverflow.com/users/487362/ipapadop">ipapadop</a> in his answer to demangle types.  But on MSVC I\'m trusting <code>typeid</code> to demangle names (untested).  And this core is wrapped around some simple testing that detects, restores and reports cv-qualifiers and references to the input type.</p>\n<pre><code>#include &lt;type_traits&gt;\n#include &lt;typeinfo&gt;\n#ifndef _MSC_VER\n#   include &lt;cxxabi.h&gt;\n#endif\n#include &lt;memory&gt;\n#include &lt;string&gt;\n#include &lt;cstdlib&gt;\n\ntemplate &lt;class T&gt;\nstd::string\ntype_name()\n{\n    typedef typename std::remove_reference&lt;T&gt;::type TR;\n    std::unique_ptr&lt;char, void(*)(void*)&gt; own\n           (\n#ifndef _MSC_VER\n                abi::__cxa_demangle(typeid(TR).name(), nullptr,\n                                           nullptr, nullptr),\n#else\n                nullptr,\n#endif\n                std::free\n           );\n    std::string r = own != nullptr ? own.get() : typeid(TR).name();\n    if (std::is_const&lt;TR&gt;::value)\n        r += &quot; const&quot;;\n    if (std::is_volatile&lt;TR&gt;::value)\n        r += &quot; volatile&quot;;\n    if (std::is_lvalue_reference&lt;T&gt;::value)\n        r += &quot;&amp;&quot;;\n    else if (std::is_rvalue_reference&lt;T&gt;::value)\n        r += &quot;&amp;&amp;&quot;;\n    return r;\n}\n</code></pre>\n<p><strong>The Results</strong></p>\n<p>With this solution I can do this:</p>\n<pre><code>int&amp; foo_lref();\nint&amp;&amp; foo_rref();\nint foo_value();\n\nint\nmain()\n{\n    int i = 0;\n    const int ci = 0;\n    std::cout &lt;&lt; &quot;decltype(i) is &quot; &lt;&lt; type_name&lt;decltype(i)&gt;() &lt;&lt; \'\\n\';\n    std::cout &lt;&lt; &quot;decltype((i)) is &quot; &lt;&lt; type_name&lt;decltype((i))&gt;() &lt;&lt; \'\\n\';\n    std::cout &lt;&lt; &quot;decltype(ci) is &quot; &lt;&lt; type_name&lt;decltype(ci)&gt;() &lt;&lt; \'\\n\';\n    std::cout &lt;&lt; &quot;decltype((ci)) is &quot; &lt;&lt; type_name&lt;decltype((ci))&gt;() &lt;&lt; \'\\n\';\n    std::cout &lt;&lt; &quot;decltype(static_cast&lt;int&amp;&gt;(i)) is &quot; &lt;&lt; type_name&lt;decltype(static_cast&lt;int&amp;&gt;(i))&gt;() &lt;&lt; \'\\n\';\n    std::cout &lt;&lt; &quot;decltype(static_cast&lt;int&amp;&amp;&gt;(i)) is &quot; &lt;&lt; type_name&lt;decltype(static_cast&lt;int&amp;&amp;&gt;(i))&gt;() &lt;&lt; \'\\n\';\n    std::cout &lt;&lt; &quot;decltype(static_cast&lt;int&gt;(i)) is &quot; &lt;&lt; type_name&lt;decltype(static_cast&lt;int&gt;(i))&gt;() &lt;&lt; \'\\n\';\n    std::cout &lt;&lt; &quot;decltype(foo_lref()) is &quot; &lt;&lt; type_name&lt;decltype(foo_lref())&gt;() &lt;&lt; \'\\n\';\n    std::cout &lt;&lt; &quot;decltype(foo_rref()) is &quot; &lt;&lt; type_name&lt;decltype(foo_rref())&gt;() &lt;&lt; \'\\n\';\n    std::cout &lt;&lt; &quot;decltype(foo_value()) is &quot; &lt;&lt; type_name&lt;decltype(foo_value())&gt;() &lt;&lt; \'\\n\';\n}\n</code></pre>\n<p>and the output is:</p>\n<pre><code>decltype(i) is int\ndecltype((i)) is int&amp;\ndecltype(ci) is int const\ndecltype((ci)) is int const&amp;\ndecltype(static_cast&lt;int&amp;&gt;(i)) is int&amp;\ndecltype(static_cast&lt;int&amp;&amp;&gt;(i)) is int&amp;&amp;\ndecltype(static_cast&lt;int&gt;(i)) is int\ndecltype(foo_lref()) is int&amp;\ndecltype(foo_rref()) is int&amp;&amp;\ndecltype(foo_value()) is int\n</code></pre>\n<p>Note (for example) the difference between <code>decltype(i)</code> and <code>decltype((i))</code>.  The former is the type of the <em>declaration</em> of <code>i</code>.  The latter is the &quot;type&quot; of the <em>expression</em> <code>i</code>. (expressions never have reference type, but as a convention <code>decltype</code> represents lvalue expressions with lvalue references).</p>\n<p>Thus this tool is an excellent vehicle just to learn about <code>decltype</code>, in addition to exploring and debugging your own code.</p>\n<p>In contrast, if I were to build this just on <code>typeid(a).name()</code>, without adding back lost cv-qualifiers or references, the output would be:</p>\n<pre><code>decltype(i) is int\ndecltype((i)) is int\ndecltype(ci) is int\ndecltype((ci)) is int\ndecltype(static_cast&lt;int&amp;&gt;(i)) is int\ndecltype(static_cast&lt;int&amp;&amp;&gt;(i)) is int\ndecltype(static_cast&lt;int&gt;(i)) is int\ndecltype(foo_lref()) is int\ndecltype(foo_rref()) is int\ndecltype(foo_value()) is int\n</code></pre>\n<p>I.e. Every reference and cv-qualifier is stripped off.</p>\n<p><strong>C++14 Update</strong></p>\n<p>Just when you think you\'ve got a solution to a problem nailed, someone always comes out of nowhere and shows you a much better way. :-)</p>\n<p><a href="https://stackoverflow.com/a/35943472/576911">This answer</a> from <a href="https://stackoverflow.com/users/2969631/jamboree">Jamboree</a> shows how to get the type name in C++14 at compile time.  It is a brilliant solution for a couple reasons:</p>\n<ol>\n<li>It\'s at compile time!</li>\n<li>You get the compiler itself to do the job instead of a library (even a std::lib).  This means more accurate results for the latest language features (like lambdas).</li>\n</ol>\n<p><a href="https://stackoverflow.com/users/2969631/jamboree">Jamboree\'s</a> <a href="https://stackoverflow.com/a/35943472/576911">answer</a> doesn\'t quite lay everything out for VS, and I\'m tweaking his code a little bit.  But since this answer gets a lot of views, take some time to go over there and upvote his answer, without which, this update would never have happened.</p>\n<pre><code>#include &lt;cstddef&gt;\n#include &lt;stdexcept&gt;\n#include &lt;cstring&gt;\n#include &lt;ostream&gt;\n\n#ifndef _MSC_VER\n#  if __cplusplus &lt; 201103\n#    define CONSTEXPR11_TN\n#    define CONSTEXPR14_TN\n#    define NOEXCEPT_TN\n#  elif __cplusplus &lt; 201402\n#    define CONSTEXPR11_TN constexpr\n#    define CONSTEXPR14_TN\n#    define NOEXCEPT_TN noexcept\n#  else\n#    define CONSTEXPR11_TN constexpr\n#    define CONSTEXPR14_TN constexpr\n#    define NOEXCEPT_TN noexcept\n#  endif\n#else  // _MSC_VER\n#  if _MSC_VER &lt; 1900\n#    define CONSTEXPR11_TN\n#    define CONSTEXPR14_TN\n#    define NOEXCEPT_TN\n#  elif _MSC_VER &lt; 2000\n#    define CONSTEXPR11_TN constexpr\n#    define CONSTEXPR14_TN\n#    define NOEXCEPT_TN noexcept\n#  else\n#    define CONSTEXPR11_TN constexpr\n#    define CONSTEXPR14_TN constexpr\n#    define NOEXCEPT_TN noexcept\n#  endif\n#endif  // _MSC_VER\n\nclass static_string\n{\n    const char* const p_;\n    const std::size_t sz_;\n\npublic:\n    typedef const char* const_iterator;\n\n    template &lt;std::size_t N&gt;\n    CONSTEXPR11_TN static_string(const char(&amp;a)[N]) NOEXCEPT_TN\n        : p_(a)\n        , sz_(N-1)\n        {}\n\n    CONSTEXPR11_TN static_string(const char* p, std::size_t N) NOEXCEPT_TN\n        : p_(p)\n        , sz_(N)\n        {}\n\n    CONSTEXPR11_TN const char* data() const NOEXCEPT_TN {return p_;}\n    CONSTEXPR11_TN std::size_t size() const NOEXCEPT_TN {return sz_;}\n\n    CONSTEXPR11_TN const_iterator begin() const NOEXCEPT_TN {return p_;}\n    CONSTEXPR11_TN const_iterator end()   const NOEXCEPT_TN {return p_ + sz_;}\n\n    CONSTEXPR11_TN char operator[](std::size_t n) const\n    {\n        return n &lt; sz_ ? p_[n] : throw std::out_of_range(&quot;static_string&quot;);\n    }\n};\n\ninline\nstd::ostream&amp;\noperator&lt;&lt;(std::ostream&amp; os, static_string const&amp; s)\n{\n    return os.write(s.data(), s.size());\n}\n\ntemplate &lt;class T&gt;\nCONSTEXPR14_TN\nstatic_string\ntype_name()\n{\n#ifdef __clang__\n    static_string p = __PRETTY_FUNCTION__;\n    return static_string(p.data() + 31, p.size() - 31 - 1);\n#elif defined(__GNUC__)\n    static_string p = __PRETTY_FUNCTION__;\n#  if __cplusplus &lt; 201402\n    return static_string(p.data() + 36, p.size() - 36 - 1);\n#  else\n    return static_string(p.data() + 46, p.size() - 46 - 1);\n#  endif\n#elif defined(_MSC_VER)\n    static_string p = __FUNCSIG__;\n    return static_string(p.data() + 38, p.size() - 38 - 7);\n#endif\n}\n</code></pre>\n<p>This code will auto-backoff on the <code>constexpr</code> if you\'re still stuck in ancient C++11.  And if you\'re painting on the cave wall with C++98/03, the <code>noexcept</code> is sacrificed as well.</p>\n<p><strong>C++17 Update</strong></p>\n<p>In the comments below <a href="https://stackoverflow.com/users/3624760/lyberta">Lyberta</a> points out that the new <code>std::string_view</code> can replace <code>static_string</code>:</p>\n<pre><code>template &lt;class T&gt;\nconstexpr\nstd::string_view\ntype_name()\n{\n    using namespace std;\n#ifdef __clang__\n    string_view p = __PRETTY_FUNCTION__;\n    return string_view(p.data() + 34, p.size() - 34 - 1);\n#elif defined(__GNUC__)\n    string_view p = __PRETTY_FUNCTION__;\n#  if __cplusplus &lt; 201402\n    return string_view(p.data() + 36, p.size() - 36 - 1);\n#  else\n    return string_view(p.data() + 49, p.find(\';\', 49) - 49);\n#  endif\n#elif defined(_MSC_VER)\n    string_view p = __FUNCSIG__;\n    return string_view(p.data() + 84, p.size() - 84 - 7);\n#endif\n}\n</code></pre>\n<p>I\'ve updated the constants for VS thanks to the very nice detective work by Jive Dadson in the comments below.</p>\n<h2>Update:</h2>\n<p>Be sure to check out <a href="https://stackoverflow.com/a/56766138/576911">this</a> rewrite or <a href="https://stackoverflow.com/a/64490578/576911">this</a> rewrite below which eliminate the unreadable magic numbers in my latest formulation.</p>\n'}, {'answer_id': 29040615, 'author': 'Jahid', 'author_id': 3744681, 'author_profile': 'https://Stackoverflow.com/users/3744681', 'pm_score': 3, 'selected': False, 'text': '<p>I like Nick\'s method, A complete form might be this (for all basic data types):</p>\n\n<pre><code>template &lt;typename T&gt; const char* typeof(T&amp;) { return "unknown"; }    // default\ntemplate&lt;&gt; const char* typeof(int&amp;) { return "int"; }\ntemplate&lt;&gt; const char* typeof(short&amp;) { return "short"; }\ntemplate&lt;&gt; const char* typeof(long&amp;) { return "long"; }\ntemplate&lt;&gt; const char* typeof(unsigned&amp;) { return "unsigned"; }\ntemplate&lt;&gt; const char* typeof(unsigned short&amp;) { return "unsigned short"; }\ntemplate&lt;&gt; const char* typeof(unsigned long&amp;) { return "unsigned long"; }\ntemplate&lt;&gt; const char* typeof(float&amp;) { return "float"; }\ntemplate&lt;&gt; const char* typeof(double&amp;) { return "double"; }\ntemplate&lt;&gt; const char* typeof(long double&amp;) { return "long double"; }\ntemplate&lt;&gt; const char* typeof(std::string&amp;) { return "String"; }\ntemplate&lt;&gt; const char* typeof(char&amp;) { return "char"; }\ntemplate&lt;&gt; const char* typeof(signed char&amp;) { return "signed char"; }\ntemplate&lt;&gt; const char* typeof(unsigned char&amp;) { return "unsigned char"; }\ntemplate&lt;&gt; const char* typeof(char*&amp;) { return "char*"; }\ntemplate&lt;&gt; const char* typeof(signed char*&amp;) { return "signed char*"; }\ntemplate&lt;&gt; const char* typeof(unsigned char*&amp;) { return "unsigned char*"; }\n</code></pre>\n'}, {'answer_id': 29043884, 'author': 'Jahid', 'author_id': 3744681, 'author_profile': 'https://Stackoverflow.com/users/3744681', 'pm_score': 3, 'selected': False, 'text': '<p>A more generic solution without function overloading than my previous one:</p>\n\n<pre><code>template&lt;typename T&gt;\nstd::string TypeOf(T){\n    std::string Type="unknown";\n    if(std::is_same&lt;T,int&gt;::value) Type="int";\n    if(std::is_same&lt;T,std::string&gt;::value) Type="String";\n    if(std::is_same&lt;T,MyClass&gt;::value) Type="MyClass";\n\n    return Type;}\n</code></pre>\n\n<p>Here MyClass is user defined class. More conditions can be added here as well.</p>\n\n<p>Example:</p>\n\n<pre><code>#include &lt;iostream&gt;\n\n\n\nclass MyClass{};\n\n\ntemplate&lt;typename T&gt;\nstd::string TypeOf(T){\n    std::string Type="unknown";\n    if(std::is_same&lt;T,int&gt;::value) Type="int";\n    if(std::is_same&lt;T,std::string&gt;::value) Type="String";\n    if(std::is_same&lt;T,MyClass&gt;::value) Type="MyClass";\n    return Type;}\n\n\nint main(){;\n    int a=0;\n    std::string s="";\n    MyClass my;\n    std::cout&lt;&lt;TypeOf(a)&lt;&lt;std::endl;\n    std::cout&lt;&lt;TypeOf(s)&lt;&lt;std::endl;\n    std::cout&lt;&lt;TypeOf(my)&lt;&lt;std::endl;\n\n    return 0;}\n</code></pre>\n\n<p>Output:</p>\n\n<pre><code>int\nString\nMyClass\n</code></pre>\n'}, {'answer_id': 35703301, 'author': 'Alan', 'author_id': 1691719, 'author_profile': 'https://Stackoverflow.com/users/1691719', 'pm_score': 3, 'selected': False, 'text': '<p>You may also use c++filt with option -t (type) to demangle the type name:</p>\n\n<pre><code>#include &lt;iostream&gt;\n#include &lt;typeinfo&gt;\n#include &lt;string&gt;\n\nusing namespace std;\n\nint main() {\n  auto x = 1;\n  string my_type = typeid(x).name();\n  system(("echo " + my_type + " | c++filt -t").c_str());\n  return 0;\n}\n</code></pre>\n\n<p>Tested on linux only.</p>\n'}, {'answer_id': 39937286, 'author': 'abodeofcode', 'author_id': 6942726, 'author_profile': 'https://Stackoverflow.com/users/6942726', 'pm_score': 4, 'selected': False, 'text': '<p>In C++11, we have decltype. There is no way in standard c++ to display exact type of variable declared using decltype. We can use boost typeindex i.e <code>type_id_with_cvr</code> (cvr stands for const, volatile, reference) to print type like below.</p>\n\n<pre><code>#include &lt;iostream&gt;\n#include &lt;boost/type_index.hpp&gt;\n\nusing namespace std;\nusing boost::typeindex::type_id_with_cvr;\n\nint main() {\n  int i = 0;\n  const int ci = 0;\n  cout &lt;&lt; "decltype(i) is " &lt;&lt; type_id_with_cvr&lt;decltype(i)&gt;().pretty_name() &lt;&lt; \'\\n\';\n  cout &lt;&lt; "decltype((i)) is " &lt;&lt; type_id_with_cvr&lt;decltype((i))&gt;().pretty_name() &lt;&lt; \'\\n\';\n  cout &lt;&lt; "decltype(ci) is " &lt;&lt; type_id_with_cvr&lt;decltype(ci)&gt;().pretty_name() &lt;&lt; \'\\n\';\n  cout &lt;&lt; "decltype((ci)) is " &lt;&lt; type_id_with_cvr&lt;decltype((ci))&gt;().pretty_name() &lt;&lt; \'\\n\';\n  cout &lt;&lt; "decltype(std::move(i)) is " &lt;&lt; type_id_with_cvr&lt;decltype(std::move(i))&gt;().pretty_name() &lt;&lt; \'\\n\';\n  cout &lt;&lt; "decltype(std::static_cast&lt;int&amp;&amp;&gt;(i)) is " &lt;&lt; type_id_with_cvr&lt;decltype(static_cast&lt;int&amp;&amp;&gt;(i))&gt;().pretty_name() &lt;&lt; \'\\n\';\n  return 0;\n}\n</code></pre>\n'}, {'answer_id': 45457278, 'author': 'Graywolf', 'author_id': 7138477, 'author_profile': 'https://Stackoverflow.com/users/7138477', 'pm_score': 2, 'selected': False, 'text': '<pre><code>#include &lt;iostream&gt;\n#include &lt;typeinfo&gt;\nusing namespace std;\n#define show_type_name(_t) \\\n    system(("echo " + string(typeid(_t).name()) + " | c++filt -t").c_str())\n\nint main() {\n    auto a = {"one", "two", "three"};\n    cout &lt;&lt; "Type of a: " &lt;&lt; typeid(a).name() &lt;&lt; endl;\n    cout &lt;&lt; "Real type of a:\\n";\n    show_type_name(a);\n    for (auto s : a) {\n        if (string(s) == "one") {\n            cout &lt;&lt; "Type of s: " &lt;&lt; typeid(s).name() &lt;&lt; endl;\n            cout &lt;&lt; "Real type of s:\\n";\n            show_type_name(s);\n        }\n        cout &lt;&lt; s &lt;&lt; endl;\n    }\n\n    int i = 5;\n    cout &lt;&lt; "Type of i: " &lt;&lt; typeid(i).name() &lt;&lt; endl;\n    cout &lt;&lt; "Real type of i:\\n";\n    show_type_name(i);\n    return 0;\n}\n</code></pre>\n\n<p>Output:</p>\n\n<pre><code>Type of a: St16initializer_listIPKcE\nReal type of a:\nstd::initializer_list&lt;char const*&gt;\nType of s: PKc\nReal type of s:\nchar const*\none\ntwo\nthree\nType of i: i\nReal type of i:\nint\n</code></pre>\n'}, {'answer_id': 45743053, 'author': 'HolyBlackCat', 'author_id': 2752075, 'author_profile': 'https://Stackoverflow.com/users/2752075', 'pm_score': 3, 'selected': False, 'text': "<p>As I challenge I decided to test how far can one go with platform-independent (hopefully) template trickery.</p>\n\n<p>The names are assembled completely at compilation time. (Which means <code>typeid(T).name()</code> couldn't be used, thus you have to explicitly provide names for non-compound types. Otherwise placeholders will be displayed instead.)</p>\n\n<p>Example usage:</p>\n\n<pre><code>TYPE_NAME(int)\nTYPE_NAME(void)\n// You probably should list all primitive types here.\n\nTYPE_NAME(std::string)\n\nint main()\n{\n    // A simple case\n    std::cout &lt;&lt; type_name&lt;void(*)(int)&gt; &lt;&lt; '\\n';\n    // -&gt; `void (*)(int)`\n\n    // Ugly mess case\n    // Note that compiler removes cv-qualifiers from parameters and replaces arrays with pointers.\n    std::cout &lt;&lt; type_name&lt;void (std::string::*(int[3],const int, void (*)(std::string)))(volatile int*const*)&gt; &lt;&lt; '\\n';\n    // -&gt; `void (std::string::*(int *,int,void (*)(std::string)))(volatile int *const*)`\n\n    // A case with undefined types\n    //  If a type wasn't TYPE_NAME'd, it's replaced by a placeholder, one of `class?`, `union?`, `enum?` or `??`.\n    std::cout &lt;&lt; type_name&lt;std::ostream (*)(int, short)&gt; &lt;&lt; '\\n';\n    // -&gt; `class? (*)(int,??)`\n    // With appropriate TYPE_NAME's, the output would be `std::string (*)(int,short)`.\n}\n</code></pre>\n\n<p>Code:</p>\n\n<pre><code>#include &lt;type_traits&gt;\n#include &lt;utility&gt;\n\nstatic constexpr std::size_t max_str_lit_len = 256;\n\ntemplate &lt;std::size_t I, std::size_t N&gt; constexpr char sl_at(const char (&amp;str)[N])\n{\n    if constexpr(I &lt; N)\n        return str[I];\n    else\n        return '\\0';\n}\n\nconstexpr std::size_t sl_len(const char *str)\n{\n    for (std::size_t i = 0; i &lt; max_str_lit_len; i++)\n        if (str[i] == '\\0')\n            return i;\n    return 0;\n}\n\ntemplate &lt;char ...C&gt; struct str_lit\n{\n    static constexpr char value[] {C..., '\\0'};\n    static constexpr int size = sl_len(value);\n\n    template &lt;typename F, typename ...P&gt; struct concat_impl {using type = typename concat_impl&lt;F&gt;::type::template concat_impl&lt;P...&gt;::type;};\n    template &lt;char ...CC&gt; struct concat_impl&lt;str_lit&lt;CC...&gt;&gt; {using type = str_lit&lt;C..., CC...&gt;;};\n    template &lt;typename ...P&gt; using concat = typename concat_impl&lt;P...&gt;::type;\n};\n\ntemplate &lt;typename, const char *&gt; struct trim_str_lit_impl;\ntemplate &lt;std::size_t ...I, const char *S&gt; struct trim_str_lit_impl&lt;std::index_sequence&lt;I...&gt;, S&gt;\n{\n    using type = str_lit&lt;S[I]...&gt;;\n};\ntemplate &lt;std::size_t N, const char *S&gt; using trim_str_lit = typename trim_str_lit_impl&lt;std::make_index_sequence&lt;N&gt;, S&gt;::type;\n\n#define STR_LIT(str) ::trim_str_lit&lt;::sl_len(str), ::str_lit&lt;STR_TO_VA(str)&gt;::value&gt;\n#define STR_TO_VA(str) STR_TO_VA_16(str,0),STR_TO_VA_16(str,16),STR_TO_VA_16(str,32),STR_TO_VA_16(str,48)\n#define STR_TO_VA_16(str,off) STR_TO_VA_4(str,0+off),STR_TO_VA_4(str,4+off),STR_TO_VA_4(str,8+off),STR_TO_VA_4(str,12+off)\n#define STR_TO_VA_4(str,off) ::sl_at&lt;off+0&gt;(str),::sl_at&lt;off+1&gt;(str),::sl_at&lt;off+2&gt;(str),::sl_at&lt;off+3&gt;(str)\n\ntemplate &lt;char ...C&gt; constexpr str_lit&lt;C...&gt; make_str_lit(str_lit&lt;C...&gt;) {return {};}\ntemplate &lt;std::size_t N&gt; constexpr auto make_str_lit(const char (&amp;str)[N])\n{\n    return trim_str_lit&lt;sl_len((const char (&amp;)[N])str), str&gt;{};\n}\n\ntemplate &lt;std::size_t A, std::size_t B&gt; struct cexpr_pow {static constexpr std::size_t value = A * cexpr_pow&lt;A,B-1&gt;::value;};\ntemplate &lt;std::size_t A&gt; struct cexpr_pow&lt;A,0&gt; {static constexpr std::size_t value = 1;};\ntemplate &lt;std::size_t N, std::size_t X, typename = std::make_index_sequence&lt;X&gt;&gt; struct num_to_str_lit_impl;\ntemplate &lt;std::size_t N, std::size_t X, std::size_t ...Seq&gt; struct num_to_str_lit_impl&lt;N, X, std::index_sequence&lt;Seq...&gt;&gt;\n{\n    static constexpr auto func()\n    {\n        if constexpr (N &gt;= cexpr_pow&lt;10,X&gt;::value)\n            return num_to_str_lit_impl&lt;N, X+1&gt;::func();\n        else\n            return str_lit&lt;(N / cexpr_pow&lt;10,X-1-Seq&gt;::value % 10 + '0')...&gt;{};\n    }\n};\ntemplate &lt;std::size_t N&gt; using num_to_str_lit = decltype(num_to_str_lit_impl&lt;N,1&gt;::func());\n\n\nusing spa = str_lit&lt;' '&gt;;\nusing lpa = str_lit&lt;'('&gt;;\nusing rpa = str_lit&lt;')'&gt;;\nusing lbr = str_lit&lt;'['&gt;;\nusing rbr = str_lit&lt;']'&gt;;\nusing ast = str_lit&lt;'*'&gt;;\nusing amp = str_lit&lt;'&amp;'&gt;;\nusing con = str_lit&lt;'c','o','n','s','t'&gt;;\nusing vol = str_lit&lt;'v','o','l','a','t','i','l','e'&gt;;\nusing con_vol = con::concat&lt;spa, vol&gt;;\nusing nsp = str_lit&lt;':',':'&gt;;\nusing com = str_lit&lt;','&gt;;\nusing unk = str_lit&lt;'?','?'&gt;;\n\nusing c_cla = str_lit&lt;'c','l','a','s','s','?'&gt;;\nusing c_uni = str_lit&lt;'u','n','i','o','n','?'&gt;;\nusing c_enu = str_lit&lt;'e','n','u','m','?'&gt;;\n\ntemplate &lt;typename T&gt; inline constexpr bool ptr_or_ref = std::is_pointer_v&lt;T&gt; || std::is_reference_v&lt;T&gt; || std::is_member_pointer_v&lt;T&gt;;\ntemplate &lt;typename T&gt; inline constexpr bool func_or_arr = std::is_function_v&lt;T&gt; || std::is_array_v&lt;T&gt;;\n\ntemplate &lt;typename T&gt; struct primitive_type_name {using value = unk;};\n\ntemplate &lt;typename T, typename = std::enable_if_t&lt;std::is_class_v&lt;T&gt;&gt;&gt; using enable_if_class = T;\ntemplate &lt;typename T, typename = std::enable_if_t&lt;std::is_union_v&lt;T&gt;&gt;&gt; using enable_if_union = T;\ntemplate &lt;typename T, typename = std::enable_if_t&lt;std::is_enum_v &lt;T&gt;&gt;&gt; using enable_if_enum  = T;\ntemplate &lt;typename T&gt; struct primitive_type_name&lt;enable_if_class&lt;T&gt;&gt; {using value = c_cla;};\ntemplate &lt;typename T&gt; struct primitive_type_name&lt;enable_if_union&lt;T&gt;&gt; {using value = c_uni;};\ntemplate &lt;typename T&gt; struct primitive_type_name&lt;enable_if_enum &lt;T&gt;&gt; {using value = c_enu;};\n\ntemplate &lt;typename T&gt; struct type_name_impl;\n\ntemplate &lt;typename T&gt; using type_name_lit = std::conditional_t&lt;std::is_same_v&lt;typename primitive_type_name&lt;T&gt;::value::template concat&lt;spa&gt;,\n                                                                               typename type_name_impl&lt;T&gt;::l::template concat&lt;typename type_name_impl&lt;T&gt;::r&gt;&gt;,\n                                            typename primitive_type_name&lt;T&gt;::value,\n                                            typename type_name_impl&lt;T&gt;::l::template concat&lt;typename type_name_impl&lt;T&gt;::r&gt;&gt;;\ntemplate &lt;typename T&gt; inline constexpr const char *type_name = type_name_lit&lt;T&gt;::value;\n\ntemplate &lt;typename T, typename = std::enable_if_t&lt;!std::is_const_v&lt;T&gt; &amp;&amp; !std::is_volatile_v&lt;T&gt;&gt;&gt; using enable_if_no_cv = T;\n\ntemplate &lt;typename T&gt; struct type_name_impl\n{\n    using l = typename primitive_type_name&lt;T&gt;::value::template concat&lt;spa&gt;;\n    using r = str_lit&lt;&gt;;\n};\ntemplate &lt;typename T&gt; struct type_name_impl&lt;const T&gt;\n{\n    using new_T_l = std::conditional_t&lt;type_name_impl&lt;T&gt;::l::size &amp;&amp; !ptr_or_ref&lt;T&gt;,\n                                       spa::concat&lt;typename type_name_impl&lt;T&gt;::l&gt;,\n                                       typename type_name_impl&lt;T&gt;::l&gt;;\n    using l = std::conditional_t&lt;ptr_or_ref&lt;T&gt;,\n                                 typename new_T_l::template concat&lt;con&gt;,\n                                 con::concat&lt;new_T_l&gt;&gt;;\n    using r = typename type_name_impl&lt;T&gt;::r;\n};\ntemplate &lt;typename T&gt; struct type_name_impl&lt;volatile T&gt;\n{\n    using new_T_l = std::conditional_t&lt;type_name_impl&lt;T&gt;::l::size &amp;&amp; !ptr_or_ref&lt;T&gt;,\n                                       spa::concat&lt;typename type_name_impl&lt;T&gt;::l&gt;,\n                                       typename type_name_impl&lt;T&gt;::l&gt;;\n    using l = std::conditional_t&lt;ptr_or_ref&lt;T&gt;,\n                                 typename new_T_l::template concat&lt;vol&gt;,\n                                 vol::concat&lt;new_T_l&gt;&gt;;\n    using r = typename type_name_impl&lt;T&gt;::r;\n};\ntemplate &lt;typename T&gt; struct type_name_impl&lt;const volatile T&gt;\n{\n    using new_T_l = std::conditional_t&lt;type_name_impl&lt;T&gt;::l::size &amp;&amp; !ptr_or_ref&lt;T&gt;,\n                                       spa::concat&lt;typename type_name_impl&lt;T&gt;::l&gt;,\n                                       typename type_name_impl&lt;T&gt;::l&gt;;\n    using l = std::conditional_t&lt;ptr_or_ref&lt;T&gt;,\n                                 typename new_T_l::template concat&lt;con_vol&gt;,\n                                 con_vol::concat&lt;new_T_l&gt;&gt;;\n    using r = typename type_name_impl&lt;T&gt;::r;\n};\ntemplate &lt;typename T&gt; struct type_name_impl&lt;T *&gt;\n{\n    using l = std::conditional_t&lt;func_or_arr&lt;T&gt;,\n                                 typename type_name_impl&lt;T&gt;::l::template concat&lt;lpa, ast&gt;,\n                                 typename type_name_impl&lt;T&gt;::l::template concat&lt;     ast&gt;&gt;;\n    using r = std::conditional_t&lt;func_or_arr&lt;T&gt;,\n                                 rpa::concat&lt;typename type_name_impl&lt;T&gt;::r&gt;,\n                                             typename type_name_impl&lt;T&gt;::r&gt;;\n};\ntemplate &lt;typename T&gt; struct type_name_impl&lt;T &amp;&gt;\n{\n    using l = std::conditional_t&lt;func_or_arr&lt;T&gt;,\n                                 typename type_name_impl&lt;T&gt;::l::template concat&lt;lpa, amp&gt;,\n                                 typename type_name_impl&lt;T&gt;::l::template concat&lt;     amp&gt;&gt;;\n    using r = std::conditional_t&lt;func_or_arr&lt;T&gt;,\n                                 rpa::concat&lt;typename type_name_impl&lt;T&gt;::r&gt;,\n                                             typename type_name_impl&lt;T&gt;::r&gt;;\n};\ntemplate &lt;typename T&gt; struct type_name_impl&lt;T &amp;&amp;&gt;\n{\n    using l = std::conditional_t&lt;func_or_arr&lt;T&gt;,\n                                 typename type_name_impl&lt;T&gt;::l::template concat&lt;lpa, amp, amp&gt;,\n                                 typename type_name_impl&lt;T&gt;::l::template concat&lt;     amp, amp&gt;&gt;;\n    using r = std::conditional_t&lt;func_or_arr&lt;T&gt;,\n                                 rpa::concat&lt;typename type_name_impl&lt;T&gt;::r&gt;,\n                                             typename type_name_impl&lt;T&gt;::r&gt;;\n};\ntemplate &lt;typename T, typename C&gt; struct type_name_impl&lt;T C::*&gt;\n{\n    using l = std::conditional_t&lt;func_or_arr&lt;T&gt;,\n                                 typename type_name_impl&lt;T&gt;::l::template concat&lt;lpa, type_name_lit&lt;C&gt;, nsp, ast&gt;,\n                                 typename type_name_impl&lt;T&gt;::l::template concat&lt;     type_name_lit&lt;C&gt;, nsp, ast&gt;&gt;;\n    using r = std::conditional_t&lt;func_or_arr&lt;T&gt;,\n                                 rpa::concat&lt;typename type_name_impl&lt;T&gt;::r&gt;,\n                                             typename type_name_impl&lt;T&gt;::r&gt;;\n};\ntemplate &lt;typename T&gt; struct type_name_impl&lt;enable_if_no_cv&lt;T[]&gt;&gt;\n{\n    using l = typename type_name_impl&lt;T&gt;::l;\n    using r = lbr::concat&lt;rbr, typename type_name_impl&lt;T&gt;::r&gt;;\n};\ntemplate &lt;typename T, std::size_t N&gt; struct type_name_impl&lt;enable_if_no_cv&lt;T[N]&gt;&gt;\n{\n    using l = typename type_name_impl&lt;T&gt;::l;\n    using r = lbr::concat&lt;num_to_str_lit&lt;N&gt;, rbr, typename type_name_impl&lt;T&gt;::r&gt;;\n};\ntemplate &lt;typename T&gt; struct type_name_impl&lt;T()&gt;\n{\n    using l = typename type_name_impl&lt;T&gt;::l;\n    using r = lpa::concat&lt;rpa, typename type_name_impl&lt;T&gt;::r&gt;;\n};\ntemplate &lt;typename T, typename P1, typename ...P&gt; struct type_name_impl&lt;T(P1, P...)&gt;\n{\n    using l = typename type_name_impl&lt;T&gt;::l;\n    using r = lpa::concat&lt;type_name_lit&lt;P1&gt;,\n                          com::concat&lt;type_name_lit&lt;P&gt;&gt;..., rpa, typename type_name_impl&lt;T&gt;::r&gt;;\n};\n\n#define TYPE_NAME(t) template &lt;&gt; struct primitive_type_name&lt;t&gt; {using value = STR_LIT(#t);};\n</code></pre>\n"}, {'answer_id': 56453627, 'author': 'Milo Lu', 'author_id': 2846062, 'author_profile': 'https://Stackoverflow.com/users/2846062', 'pm_score': 3, 'selected': False, 'text': "<p>As explained by Scott Meyers in <em>Effective Modern C++</em>,</p>\n<blockquote>\n<p>Calls to <code>std::type_info::name</code> are not guaranteed to return anything sensible.</p>\n</blockquote>\n<p>The best solution is to let the compiler generate an error message during the type deduction, for example:</p>\n<pre><code>template&lt;typename T&gt;\nclass TD;\n\nint main(){\n    const int theAnswer = 32;\n    auto x = theAnswer;\n    auto y = &amp;theAnswer;\n    TD&lt;decltype(x)&gt; xType;\n    TD&lt;decltype(y)&gt; yType;\n    return 0;\n}\n</code></pre>\n<p>The result will be something like this, depending on the compilers:</p>\n<pre><code>test4.cpp:10:21: error: aggregate ‘TD&lt;int&gt; xType’ has incomplete type and cannot be defined TD&lt;decltype(x)&gt; xType;\n\ntest4.cpp:11:21: error: aggregate ‘TD&lt;const int *&gt; yType’ has incomplete type and cannot be defined TD&lt;decltype(y)&gt; yType;\n</code></pre>\n<p>Hence, we get to know that <code>x</code>'s type is <code>int</code> and <code>y</code>'s type is <code>const int*</code></p>\n"}, {'answer_id': 56766138, 'author': '康桓瑋', 'author_id': 11638718, 'author_profile': 'https://Stackoverflow.com/users/11638718', 'pm_score': 7, 'selected': False, 'text': '<p>According to <a href="https://stackoverflow.com/a/20170989/11638718">Howard</a>\'s solution, if you don\'t like the magic number, I think this is a good way to represent and it looks intuitive:</p>\n<pre><code>#include &lt;string_view&gt;\n\ntemplate &lt;typename T&gt;\nconstexpr auto type_name() {\n  std::string_view name, prefix, suffix;\n#ifdef __clang__\n  name = __PRETTY_FUNCTION__;\n  prefix = &quot;auto type_name() [T = &quot;;\n  suffix = &quot;]&quot;;\n#elif defined(__GNUC__)\n  name = __PRETTY_FUNCTION__;\n  prefix = &quot;constexpr auto type_name() [with T = &quot;;\n  suffix = &quot;]&quot;;\n#elif defined(_MSC_VER)\n  name = __FUNCSIG__;\n  prefix = &quot;auto __cdecl type_name&lt;&quot;;\n  suffix = &quot;&gt;(void)&quot;;\n#endif\n  name.remove_prefix(prefix.size());\n  name.remove_suffix(suffix.size());\n  return name;\n}\n</code></pre>\n<p><a href="https://godbolt.org/z/Mr1ercr49" rel="noreferrer">Demo.</a></p>\n'}, {'answer_id': 58331141, 'author': 'Val', 'author_id': 7163942, 'author_profile': 'https://Stackoverflow.com/users/7163942', 'pm_score': 4, 'selected': False, 'text': '<p><a href="https://stackoverflow.com/a/20170989">Howard Hinnant</a> used magic numbers to extract type name. <a href="https://stackoverflow.com/a/56766138">康桓瑋</a> suggested string prefix and suffix. But prefix/suffix  keep changing.\nWith “probe_type” type_name automatically calculates prefix and suffix sizes for “probe_type” to extract type name:</p>\n<pre><code>#include &lt;string_view&gt;\nusing namespace std;\n\nnamespace typeName {\n template &lt;typename T&gt;\n  constexpr string_view wrapped_type_name () {\n#ifdef __clang__\n    return __PRETTY_FUNCTION__;\n#elif defined(__GNUC__)\n    return  __PRETTY_FUNCTION__;\n#elif defined(_MSC_VER)\n    return  __FUNCSIG__;\n#endif\n  }\n\n  class probe_type;\n  constexpr string_view probe_type_name (&quot;typeName::probe_type&quot;);\n  constexpr string_view probe_type_name_elaborated (&quot;class typeName::probe_type&quot;);\n  constexpr string_view probe_type_name_used (wrapped_type_name&lt;probe_type&gt; ().find (probe_type_name_elaborated) != -1 ? probe_type_name_elaborated : probe_type_name);\n\n  constexpr size_t prefix_size () {\n    return wrapped_type_name&lt;probe_type&gt; ().find (probe_type_name_used);\n  }\n\n  constexpr size_t suffix_size () {\n    return wrapped_type_name&lt;probe_type&gt; ().length () - prefix_size () - probe_type_name_used.length ();\n  }\n\n  template &lt;typename T&gt;\n  string_view type_name () {\n    constexpr auto type_name = wrapped_type_name&lt;T&gt; ();\n\n    return type_name.substr (prefix_size (), type_name.length () - prefix_size () - suffix_size ());\n  }\n}\n\n#include &lt;iostream&gt;\n\nusing typeName::type_name;\nusing typeName::probe_type;\n\nclass test;\n\nint main () {\n  cout &lt;&lt; type_name&lt;class test&gt; () &lt;&lt; endl;\n\n  cout &lt;&lt; type_name&lt;const int*&amp;&gt; () &lt;&lt; endl;\n  cout &lt;&lt; type_name&lt;unsigned int&gt; () &lt;&lt; endl;\n\n  const int ic = 42;\n  const int* pic = &amp;ic;\n  const int*&amp; rpic = pic;\n  cout &lt;&lt; type_name&lt;decltype(ic)&gt; () &lt;&lt; endl;\n  cout &lt;&lt; type_name&lt;decltype(pic)&gt; () &lt;&lt; endl;\n  cout &lt;&lt; type_name&lt;decltype(rpic)&gt; () &lt;&lt; endl;\n\n  cout &lt;&lt; type_name&lt;probe_type&gt; () &lt;&lt; endl;\n}\n</code></pre>\n<p>Output</p>\n<p><a href="https://godbolt.org" rel="noreferrer">gcc 10.2</a>:</p>\n<pre><code>test\nconst int *&amp;\nunsigned int\nconst int\nconst int *\nconst int *&amp;\ntypeName::probe_type\n</code></pre>\n<p><a href="https://godbolt.org" rel="noreferrer">clang 11.0.0</a>:</p>\n<pre><code>test\nconst int *&amp;\nunsigned int\nconst int\nconst int *\nconst int *&amp;\ntypeName::probe_type\n</code></pre>\n<p>VS 2019 version 16.7.6:</p>\n<pre><code>class test\nconst int*&amp;\nunsigned int\nconst int\nconst int*\nconst int*&amp;\nclass typeName::probe_type\n</code></pre>\n'}, {'answer_id': 61344776, 'author': 'Lars Melchior', 'author_id': 2397086, 'author_profile': 'https://Stackoverflow.com/users/2397086', 'pm_score': 2, 'selected': False, 'text': '<p>For anyone still visiting, I\'ve recently had the same issue and decided to write a small library based on answers from this post. It provides constexpr type names and type indices und is is tested on Mac, Windows and Ubuntu.</p>\n\n<p>The library code is here: <a href="https://github.com/TheLartians/StaticTypeInfo" rel="nofollow noreferrer">https://github.com/TheLartians/StaticTypeInfo</a></p>\n'}, {'answer_id': 64490578, 'author': 'einpoklum', 'author_id': 1593077, 'author_profile': 'https://Stackoverflow.com/users/1593077', 'pm_score': 4, 'selected': False, 'text': '<p><sub>Another take on <a href="https://stackoverflow.com/a/56766138">@康桓瑋\'s answer</a> (originally ), making less assumptions about the prefix and suffix specifics, and inspired by <a href="https://stackoverflow.com/a/58331141/1593077">@Val\'s answer</a> - but without polluting the global namespace; without any conditions; and hopefully easier to read.</sub></p>\n<p>The popular compilers provide a macro with the current function\'s signature. Now, functions are templatable; so the signature contains the template arguments. So, the basic approach is: Given a type, be in a function with that type as a template argument.</p>\n<p>Unfortunately, the type name is wrapped in text describing the function, which is different between compilers. For example, with GCC, the signature of <code>template &lt;typename T&gt; int foo()</code> with type <code>double</code> is: <code>int foo() [T = double]</code>.</p>\n<p>So, how do you get rid of the wrapper text? @HowardHinnant\'s solution is the shortest and most &quot;direct&quot;: Just use per-compiler magic numbers to remove a prefix and a suffix. But obviously, that\'s very brittle; and nobody likes magic numbers in their code. It turns out, however, that given the macro value for a type with a known name, you can determine what prefix and suffix constitute the wrapping.</p>\n<pre class="lang-c++ prettyprint-override"><code>#include &lt;string_view&gt;\n\ntemplate &lt;typename T&gt; constexpr std::string_view type_name();\n\ntemplate &lt;&gt;\nconstexpr std::string_view type_name&lt;void&gt;()\n{ return &quot;void&quot;; }\n\nnamespace detail {\n\nusing type_name_prober = void;\n\ntemplate &lt;typename T&gt;\nconstexpr std::string_view wrapped_type_name() \n{\n#ifdef __clang__\n    return __PRETTY_FUNCTION__;\n#elif defined(__GNUC__)\n    return __PRETTY_FUNCTION__;\n#elif defined(_MSC_VER)\n    return __FUNCSIG__;\n#else\n#error &quot;Unsupported compiler&quot;\n#endif\n}\n\nconstexpr std::size_t wrapped_type_name_prefix_length() { \n    return wrapped_type_name&lt;type_name_prober&gt;().find(type_name&lt;type_name_prober&gt;()); \n}\n\nconstexpr std::size_t wrapped_type_name_suffix_length() { \n    return wrapped_type_name&lt;type_name_prober&gt;().length() \n        - wrapped_type_name_prefix_length() \n        - type_name&lt;type_name_prober&gt;().length();\n}\n\n} // namespace detail\n\ntemplate &lt;typename T&gt;\nconstexpr std::string_view type_name() {\n    constexpr auto wrapped_name = detail::wrapped_type_name&lt;T&gt;();\n    constexpr auto prefix_length = detail::wrapped_type_name_prefix_length();\n    constexpr auto suffix_length = detail::wrapped_type_name_suffix_length();\n    constexpr auto type_name_length = wrapped_name.length() - prefix_length - suffix_length;\n    return wrapped_name.substr(prefix_length, type_name_length);\n}\n</code></pre>\n<p>See it on <a href="https://godbolt.org/z/3ac5f5" rel="noreferrer"><kbd>GodBolt</kbd></a>. This should be working with MSVC as well.</p>\n'}, {'answer_id': 64717914, 'author': 'CourageousPotato', 'author_id': 11502722, 'author_profile': 'https://Stackoverflow.com/users/11502722', 'pm_score': 1, 'selected': False, 'text': '<p>Copying from this answer: <a href="https://stackoverflow.com/a/56766138/11502722">https://stackoverflow.com/a/56766138/11502722</a></p>\n<p>I was able to get this <em>somewhat</em> working for C++ <code>static_assert()</code>. The wrinkle here is that <code>static_assert()</code> only accepts string literals; <code>constexpr string_view</code> will not work. You will need to accept extra text around the typename, but it works:</p>\n<pre class="lang-cpp prettyprint-override"><code>template&lt;typename T&gt;\nconstexpr void assertIfTestFailed()\n{\n#ifdef __clang__\n    static_assert(testFn&lt;T&gt;(), &quot;Test failed on this used type: &quot; __PRETTY_FUNCTION__);\n#elif defined(__GNUC__)\n    static_assert(testFn&lt;T&gt;(), &quot;Test failed on this used type: &quot; __PRETTY_FUNCTION__);\n#elif defined(_MSC_VER)\n    static_assert(testFn&lt;T&gt;(), &quot;Test failed on this used type: &quot; __FUNCSIG__);\n#else\n    static_assert(testFn&lt;T&gt;(), &quot;Test failed on this used type (see surrounding logged error for details).&quot;);\n#endif\n    }\n}\n</code></pre>\n<p>MSVC Output:</p>\n<pre><code>error C2338: Test failed on this used type: void __cdecl assertIfTestFailed&lt;class BadType&gt;(void)\n... continued trace of where the erroring code came from ...\n</code></pre>\n'}, {'answer_id': 67562646, 'author': 'Chris Uzdavinis', 'author_id': 8309701, 'author_profile': 'https://Stackoverflow.com/users/8309701', 'pm_score': 2, 'selected': False, 'text': '<p>For something different, here\'s a &quot;To English&quot; conversion of the type, deconstructing every qualifier, extent, argument, and so on, recursively building the string describing the type  I think the &quot;deduced this&quot; proposal would help cut down many of the specializations.  In any case, this was a fun morning exercise, regardless of excessive bloat. :)</p>\n<pre><code>struct X {\n    using T = int *((*)[10]);\n    T f(T, const unsigned long long * volatile * );\n};\n\nint main() {\n\n    std::cout &lt;&lt; describe&lt;decltype(&amp;X::f)&gt;() &lt;&lt; std::endl;\n}\n</code></pre>\n<p>Output:</p>\n<pre><code>pointer to member function of class 1X taking (pointer to array[10]\nof pointer to int, pointer to volatile pointer to const unsigned \nlong long), and returning pointer to array[10] of pointer to int\n</code></pre>\n<p>Here\'s the code:\n<a href="https://godbolt.org/z/7jKK4or43" rel="nofollow noreferrer">https://godbolt.org/z/7jKK4or43</a></p>\n<p><strong>Note</strong>: most current version is in my github: <a href="https://github.com/cuzdav/type_to_string" rel="nofollow noreferrer">https://github.com/cuzdav/type_to_string</a></p>\n<pre class="lang-cpp prettyprint-override"><code>// Print types as strings, including functions, member \n\n#include &lt;type_traits&gt;\n#include &lt;typeinfo&gt;\n#include &lt;string&gt;\n#include &lt;utility&gt;\n\nnamespace detail {\n\ntemplate &lt;typename T&gt; struct Describe;\n\ntemplate &lt;typename T, class ClassT&gt; \nstruct Describe&lt;T (ClassT::*)&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ArgsT...)&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...)&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) volatile&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) volatile noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...)&amp;&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const &amp;&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) volatile &amp;&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) &amp; noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile &amp;&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const &amp; noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) volatile &amp; noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile &amp; noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) &amp;&amp;&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const &amp;&amp;&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) volatile &amp;&amp;&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) &amp;&amp; noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile &amp;&amp;&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const &amp;&amp; noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) volatile &amp;&amp; noexcept&gt;  {\n    static std::string describe();\n};\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstruct Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile &amp;&amp; noexcept&gt;  {\n    static std::string describe();\n};\n\ntemplate &lt;typename T&gt;\nstd::string describe()\n{\n    using namespace std::string_literals;\n    auto terminal = [&amp;](char const * desc) {\n        return desc + &quot; &quot;s + typeid(T).name();\n    };\n    if constexpr(std::is_const_v&lt;T&gt;) {\n        return &quot;const &quot; + describe&lt;std::remove_const_t&lt;T&gt;&gt;();\n    }\n    else if constexpr(std::is_volatile_v&lt;T&gt;) {\n        return &quot;volatile &quot; + describe&lt;std::remove_volatile_t&lt;T&gt;&gt;();\n    }\n    else if constexpr (std::is_same_v&lt;bool, T&gt;) {\n        return &quot;bool&quot;;\n    }\n    else if constexpr(std::is_same_v&lt;char, T&gt;) {\n        return &quot;char&quot;;\n    }\n    else if constexpr(std::is_same_v&lt;signed char, T&gt;) {\n        return &quot;signed char&quot;;\n    }\n    else if constexpr(std::is_same_v&lt;unsigned char, T&gt;) {\n        return &quot;unsigned char&quot;;\n    }\n    else if constexpr(std::is_unsigned_v&lt;T&gt;) {\n        return &quot;unsigned &quot; + describe&lt;std::make_signed_t&lt;T&gt;&gt;();\n    }\n    else if constexpr(std::is_void_v&lt;T&gt;) {\n        return &quot;void&quot;;\n    }\n    else if constexpr(std::is_integral_v&lt;T&gt;) {\n        if constexpr(std::is_same_v&lt;short, T&gt;) \n            return &quot;short&quot;;\n        else if constexpr(std::is_same_v&lt;int, T&gt;) \n            return &quot;int&quot;;\n        else if constexpr(std::is_same_v&lt;long, T&gt;) \n            return &quot;long&quot;;\n        else if constexpr(std::is_same_v&lt;long long, T&gt;) \n            return &quot;long long&quot;;\n    }\n    else if constexpr(std::is_same_v&lt;float, T&gt;) {\n        return &quot;float&quot;;\n    }\n    else if constexpr(std::is_same_v&lt;double, T&gt;) {\n        return &quot;double&quot;;\n    }\n    else if constexpr(std::is_same_v&lt;long double, T&gt;) {\n        return &quot;long double&quot;;\n    }\n    else if constexpr(std::is_same_v&lt;std::nullptr_t, T&gt;) { \n        return &quot;nullptr_t&quot;;\n    }\n    else if constexpr(std::is_class_v&lt;T&gt;) {\n        return terminal(&quot;class&quot;);\n    }\n    else if constexpr(std::is_union_v&lt;T&gt;) {\n        return terminal(&quot;union&quot;);\n    }\n    else if constexpr(std::is_enum_v&lt;T&gt;) {\n        std::string result;\n        if (!std::is_convertible_v&lt;T, std::underlying_type_t&lt;T&gt;&gt;) {\n            result += &quot;scoped &quot;;\n        }\n        return result + terminal(&quot;enum&quot;);\n    }  \n    else if constexpr(std::is_pointer_v&lt;T&gt;) {\n        return &quot;pointer to &quot; + describe&lt;std::remove_pointer_t&lt;T&gt;&gt;();\n    }\n    else if constexpr(std::is_lvalue_reference_v&lt;T&gt;) {\n        return &quot;lvalue-ref to &quot; + describe&lt;std::remove_reference_t&lt;T&gt;&gt;();\n    }\n    else if constexpr(std::is_rvalue_reference_v&lt;T&gt;) {\n        return &quot;rvalue-ref to &quot; + describe&lt;std::remove_reference_t&lt;T&gt;&gt;();\n    }\n    else if constexpr(std::is_bounded_array_v&lt;T&gt;) {\n        return &quot;array[&quot; + std::to_string(std::extent_v&lt;T&gt;) + &quot;] of &quot; +\n            describe&lt;std::remove_extent_t&lt;T&gt;&gt;();\n    }\n    else if constexpr(std::is_unbounded_array_v&lt;T&gt;) {\n        return &quot;array[] of &quot; + describe&lt;std::remove_extent_t&lt;T&gt;&gt;();\n    }\n    else if constexpr(std::is_function_v&lt;T&gt;) {\n        return Describe&lt;T&gt;::describe();\n    }\n    else if constexpr(std::is_member_object_pointer_v&lt;T&gt;) {\n        return Describe&lt;T&gt;::describe();\n    }\n    else if constexpr(std::is_member_function_pointer_v&lt;T&gt;) {\n        return Describe&lt;T&gt;::describe();\n    }\n}\n\ntemplate &lt;typename RetT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ArgsT...)&gt;::describe() {\n    std::string result = &quot;function taking (&quot;;\n    ((result += detail::describe&lt;ArgsT&gt;(&quot;, &quot;)), ...);\n    return result + &quot;), returning &quot; + detail::describe&lt;RetT&gt;();\n}\n\ntemplate &lt;typename T, class ClassT&gt; \nstd::string Describe&lt;T (ClassT::*)&gt;::describe() {\n    return &quot;pointer to member of &quot; + detail::describe&lt;ClassT&gt;() +\n        &quot; of type &quot; + detail::describe&lt;T&gt;();\n}\n\nstruct Comma {\n    char const * sep = &quot;&quot;;\n    std::string operator()(std::string const&amp; str) {\n        return std::exchange(sep, &quot;, &quot;) + str;\n    }\n};\nenum Qualifiers {NONE=0, CONST=1, VOLATILE=2, NOEXCEPT=4, LVREF=8, RVREF=16};\n\ntemplate &lt;typename RetT, typename ClassT, typename... ArgsT&gt;\nstd::string describeMemberPointer(Qualifiers q) {\n    std::string result = &quot;pointer to &quot;;\n    if (NONE != (q &amp; CONST)) result += &quot;const &quot;;\n    if (NONE != (q &amp; VOLATILE)) result += &quot;volatile &quot;;\n    if (NONE != (q &amp; NOEXCEPT)) result += &quot;noexcept &quot;;\n    if (NONE != (q &amp; LVREF)) result += &quot;lvalue-ref &quot;;\n    if (NONE != (q &amp; RVREF)) result += &quot;rvalue-ref &quot;;\n    result += &quot;member function of &quot; + detail::describe&lt;ClassT&gt;() + &quot; taking (&quot;;\n    Comma comma;\n    ((result += comma(detail::describe&lt;ArgsT&gt;())), ...);\n    return result + &quot;), and returning &quot; + detail::describe&lt;RetT&gt;();\n}\n\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...)&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(NONE);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(CONST);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) volatile&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(VOLATILE);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) volatile noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(VOLATILE | NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(CONST | VOLATILE);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(CONST | NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(CONST | VOLATILE | NOEXCEPT);\n}\n\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) &amp;&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(LVREF);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const &amp;&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(LVREF | CONST);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) &amp; noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(LVREF | NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) volatile &amp;&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(LVREF | VOLATILE);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) volatile &amp; noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(LVREF | VOLATILE | NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile &amp;&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(LVREF | CONST | VOLATILE);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const &amp; noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(LVREF | CONST | NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile &amp; noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(LVREF | CONST | VOLATILE | NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...)&amp;&amp;&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(RVREF);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const &amp;&amp;&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(RVREF | CONST);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) &amp;&amp; noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(RVREF | NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) volatile &amp;&amp;&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(RVREF | VOLATILE);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) volatile &amp;&amp; noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(RVREF | VOLATILE | NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile &amp;&amp;&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(RVREF | CONST | VOLATILE);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const &amp;&amp; noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(RVREF | CONST | NOEXCEPT);\n}\ntemplate &lt;typename RetT, class ClassT, typename... ArgsT&gt; \nstd::string Describe&lt;RetT(ClassT::*)(ArgsT...) const volatile &amp;&amp; noexcept&gt;::describe() {\n    return describeMemberPointer&lt;RetT, ClassT, ArgsT...&gt;(RVREF | CONST | VOLATILE | NOEXCEPT);\n}\n\n} // detail\n\n///////////////////////////////////\n// Main function\n///////////////////////////////////\ntemplate &lt;typename T&gt;\nstd::string describe() {\n    return detail::describe&lt;T&gt;();\n}\n\n\n///////////////////////////////////\n// Sample code\n///////////////////////////////////\n#include &lt;iostream&gt;\n\n\nstruct X {\n    using T = int *((*)[10]);\n    T f(T, const unsigned long long * volatile * );\n};\n\nint main() {\n    std::cout &lt;&lt; describe&lt;decltype(&amp;X::f)&gt;() &lt;&lt; std::endl;\n}\n\n</code></pre>\n'}, {'answer_id': 70839988, 'author': 'Jonas', 'author_id': 2378300, 'author_profile': 'https://Stackoverflow.com/users/2378300', 'pm_score': 1, 'selected': False, 'text': '<p>Building on a number of the previous answers, I made this solution which does not store the result of <code>__PRETTY_FUNCTION__</code> in the binary. It uses a static array to hold the string representation of the type name.</p>\n<p>It requires C++23.</p>\n<pre><code>#include &lt;iostream&gt;\n#include &lt;string_view&gt;\n#include &lt;array&gt;\n\ntemplate &lt;typename T&gt;\nconstexpr auto type_name() {\n    auto gen = [] &lt;class R&gt; () constexpr -&gt; std::string_view  {\n        return __PRETTY_FUNCTION__;\n    };\n    constexpr std::string_view search_type = &quot;float&quot;;\n    constexpr auto search_type_string = gen.template operator()&lt;float&gt;();\n    constexpr auto prefix = search_type_string.find(search_type);\n    constexpr auto suffix = search_type_string.size() - prefix - search_type.size();\n    constexpr auto str = gen.template operator()&lt;T&gt;();\n    constexpr int size = str.size() - prefix - suffix;\n    constexpr auto static arr = [&amp;]&lt;std::size_t... I&gt;(std::index_sequence&lt;I...&gt;) constexpr {\n        return std::array&lt;char, size&gt;{str[prefix + I]...};\n    } (std::make_index_sequence&lt;size&gt;{});\n\n    return std::string_view(arr.data(), size);\n}\n</code></pre>\n'}, {'answer_id': 72650356, 'author': 'Haseeb Mir', 'author_id': 6219626, 'author_profile': 'https://Stackoverflow.com/users/6219626', 'pm_score': 1, 'selected': False, 'text': '<p>C++ Data type resolve in Compile-Time using Template and Runtime using TypeId.</p>\n<p>Compile time solution.</p>\n<pre><code>template &lt;std::size_t...Idxs&gt;\nconstexpr auto substring_as_array(std::string_view str, std::index_sequence&lt;Idxs...&gt;)\n{\n  return std::array{str[Idxs]..., \'\\n\'};\n}\n\ntemplate &lt;typename T&gt;\nconstexpr auto type_name_array()\n{\n#if defined(__clang__)\n  constexpr auto prefix   = std::string_view{&quot;[T = &quot;};\n  constexpr auto suffix   = std::string_view{&quot;]&quot;};\n  constexpr auto function = std::string_view{__PRETTY_FUNCTION__};\n#elif defined(__GNUC__)\n  constexpr auto prefix   = std::string_view{&quot;with T = &quot;};\n  constexpr auto suffix   = std::string_view{&quot;]&quot;};\n  constexpr auto function = std::string_view{__PRETTY_FUNCTION__};\n#elif defined(_MSC_VER)\n  constexpr auto prefix   = std::string_view{&quot;type_name_array&lt;&quot;};\n  constexpr auto suffix   = std::string_view{&quot;&gt;(void)&quot;};\n  constexpr auto function = std::string_view{__FUNCSIG__};\n#else\n# error Unsupported compiler\n#endif\n\n  constexpr auto start = function.find(prefix) + prefix.size();\n  constexpr auto end = function.rfind(suffix);\n\n  static_assert(start &lt; end);\n\n  constexpr auto name = function.substr(start, (end - start));\n  return substring_as_array(name, std::make_index_sequence&lt;name.size()&gt;{});\n}\n\ntemplate &lt;typename T&gt;\nstruct type_name_holder {\n  static inline constexpr auto value = type_name_array&lt;T&gt;();\n};\n\ntemplate &lt;typename T&gt;\nconstexpr auto type_name() -&gt; std::string_view\n{\n  constexpr auto&amp; value = type_name_holder&lt;T&gt;::value;\n  return std::string_view{value.data(), value.size()};\n}\n</code></pre>\n<p>Runtime solution.</p>\n<pre><code>template &lt;typename T&gt;\nvoid PrintDataType(T type)\n{\n    auto name = typeid(type).name();\n    string cmd_str = &quot;echo \'&quot; + string(name) + &quot;\' | c++filt -t&quot;;\n    system(cmd_str.c_str());\n}\n</code></pre>\n<p>Main Code</p>\n<pre><code>#include &lt;iostream&gt;\n#include &lt;map&gt;\n#include &lt;string&gt;\n#include &lt;typeinfo&gt;\n#include &lt;string_view&gt;\n#include &lt;array&gt;   // std::array\n#include &lt;utility&gt; // std::index_sequence\nusing std::string;\n</code></pre>\n<blockquote>\n<pre><code>int main()\n{\n    //Dynamic resolution.\n    std::map&lt;int, int&gt; iMap;\n    PrintDataType(iMap);\n    \n    //Compile type resolution.\n    std::cout &lt;&lt; type_name&lt;std::list&lt;int&gt;&gt;() &lt;&lt; std::endl;\n\n    return 0;\n}\n</code></pre>\n</blockquote>\n<p><a href="https://gist.github.com/haseeb-heaven/d6093f68d160b92ba1c69ccd9df7ec80" rel="nofollow noreferrer">Code Snippet</a></p>\n'}, {'answer_id': 73058336, 'author': 'CPP_is_no_STANDARD', 'author_id': 18032104, 'author_profile': 'https://Stackoverflow.com/users/18032104', 'pm_score': -1, 'selected': False, 'text': '<p>Consider this code:</p>\n<pre><code>#include &lt;iostream&gt;\n\nint main()\n{\n    int a = 2; // Declare type &quot;int&quot;\n    std::string b = &quot;Hi&quot;; // Declare type &quot;string&quot;\n    long double c = 3438; // Declare type &quot;long double&quot;\n    if(typeid(a) == typeid(int))\n    {\n        std::cout&lt;&lt;&quot;int\\n&quot;;\n    }\n\n    if(typeid(b) == typeid(std::string))\n    {\n        std::cout&lt;&lt;&quot;string\\n&quot;;\n    }\n    \n    if(typeid(c) == typeid(long double))\n    {\n        std::cout&lt;&lt;&quot;long double&quot;;\n    }\n    return 0;\n}\n</code></pre>\n<p>I believe you want the whole word (rather than only printing the short form of <code>int</code> (which is <code>i</code>), you want <code>int</code>), that is why I did the <code>if</code>.</p>\n<p>For some of the variables (<code>string</code>,<code>long double</code> etc... which do not print the expected result comparing their short forms), you need to compare the result of applying the <code>typeid</code> operator with the <code>typeid</code> of a specific type.</p>\n<p>From cppreference:</p>\n<blockquote>\n<p>Returns an implementation defined null-terminated character string containing the name of the type. No guarantees are given; in particular, the returned string can be identical for several types and change between invocations of the same program.</p>\n</blockquote>\n<hr>\n<p>IMO, Python is better than C++ in this case. Python has built-in <code>type</code> function to directly access the data type of the variable.</p>\n'}]
['https://Stackoverflow.com/questions/81870', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/6508/']