例如:

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

预期的输出:

int

当前回答

另一个@康桓瑋的答案(最初),对前缀和后缀细节做了较少的假设,并受到@ val的答案的启发-但没有污染全局名称空间;无条件的:没有任何条件的;希望更容易阅读。

流行的编译器提供了带有当前函数签名的宏。现在,函数是可模板化的;因此签名包含模板参数。因此,基本的方法是:给定一个类型,在函数中使用该类型作为模板参数。

不幸的是,类型名称被包装在描述函数的文本中,这在不同的编译器中是不同的。例如,在GCC中,template <typename T> int foo()具有double类型的签名是:int foo() [T = double]。

那么,如何消除包装器文本呢?@HowardHinnant的解决方案是最简短和最“直接”的:只需使用每个编译器的魔法数字来删除前缀和后缀。但显然,这是非常脆弱的;没有人喜欢在代码中加入神奇的数字。然而,事实证明,给定具有已知名称的类型的宏值,您可以确定构成包装的前缀和后缀。

#include <string_view>

template <typename T> constexpr std::string_view type_name();

template <>
constexpr std::string_view type_name<void>()
{ return "void"; }

namespace detail {

using type_name_prober = void;

template <typename T>
constexpr std::string_view wrapped_type_name() 
{
#ifdef __clang__
    return __PRETTY_FUNCTION__;
#elif defined(__GNUC__)
    return __PRETTY_FUNCTION__;
#elif defined(_MSC_VER)
    return __FUNCSIG__;
#else
#error "Unsupported compiler"
#endif
}

constexpr std::size_t wrapped_type_name_prefix_length() { 
    return wrapped_type_name<type_name_prober>().find(type_name<type_name_prober>()); 
}

constexpr std::size_t wrapped_type_name_suffix_length() { 
    return wrapped_type_name<type_name_prober>().length() 
        - wrapped_type_name_prefix_length() 
        - type_name<type_name_prober>().length();
}

} // namespace detail

template <typename T>
constexpr std::string_view type_name() {
    constexpr auto wrapped_name = detail::wrapped_type_name<T>();
    constexpr auto prefix_length = detail::wrapped_type_name_prefix_length();
    constexpr auto suffix_length = detail::wrapped_type_name_suffix_length();
    constexpr auto type_name_length = wrapped_name.length() - prefix_length - suffix_length;
    return wrapped_name.substr(prefix_length, type_name_length);
}

可以在GodBolt上看到。这应该与MSVC工作以及。

其他回答

不要忘记包含<typeinfo>

我相信您所指的是运行时类型标识。你可以通过做来达到以上目的。

#include <iostream>
#include <typeinfo>

using namespace std;

int main() {
  int i;
  cout << typeid(i).name();
  return 0;
}

Howard Hinnant使用魔法数字提取类型名称。康桓瑋建议字符串前缀和后缀。但是前缀/后缀一直在变化。 使用" probe_type " type_name自动计算" probe_type "的前缀和后缀大小,以提取类型名称:

#include <string_view>
using namespace std;

namespace typeName {
 template <typename T>
  constexpr string_view wrapped_type_name () {
#ifdef __clang__
    return __PRETTY_FUNCTION__;
#elif defined(__GNUC__)
    return  __PRETTY_FUNCTION__;
#elif defined(_MSC_VER)
    return  __FUNCSIG__;
#endif
  }

  class probe_type;
  constexpr string_view probe_type_name ("typeName::probe_type");
  constexpr string_view probe_type_name_elaborated ("class typeName::probe_type");
  constexpr string_view probe_type_name_used (wrapped_type_name<probe_type> ().find (probe_type_name_elaborated) != -1 ? probe_type_name_elaborated : probe_type_name);

  constexpr size_t prefix_size () {
    return wrapped_type_name<probe_type> ().find (probe_type_name_used);
  }

  constexpr size_t suffix_size () {
    return wrapped_type_name<probe_type> ().length () - prefix_size () - probe_type_name_used.length ();
  }

  template <typename T>
  string_view type_name () {
    constexpr auto type_name = wrapped_type_name<T> ();

    return type_name.substr (prefix_size (), type_name.length () - prefix_size () - suffix_size ());
  }
}

#include <iostream>

using typeName::type_name;
using typeName::probe_type;

class test;

int main () {
  cout << type_name<class test> () << endl;

  cout << type_name<const int*&> () << endl;
  cout << type_name<unsigned int> () << endl;

  const int ic = 42;
  const int* pic = &ic;
  const int*& rpic = pic;
  cout << type_name<decltype(ic)> () << endl;
  cout << type_name<decltype(pic)> () << endl;
  cout << type_name<decltype(rpic)> () << endl;

  cout << type_name<probe_type> () << endl;
}

输出

gcc 10.2:

test
const int *&
unsigned int
const int
const int *
const int *&
typeName::probe_type

铿锵声11.0.0:

test
const int *&
unsigned int
const int
const int *
const int *&
typeName::probe_type

VS 2019版本16.7.6:

class test
const int*&
unsigned int
const int
const int*
const int*&
class typeName::probe_type

Try:

#include <typeinfo>

// …
std::cout << typeid(a).name() << '\n';

您可能必须在编译器选项中激活RTTI才能使其工作。此外,它的输出取决于编译器。它可能是一个原始类型名称或名称混乱符号或介于两者之间的任何东西。

您可以使用模板。

template <typename T> const char* typeof(T&) { return "unknown"; }    // default
template<> const char* typeof(int&) { return "int"; }
template<> const char* typeof(float&) { return "float"; }

在上面的例子中,当类型不匹配时,它将打印“unknown”。

根据Howard的解决方案,如果你不喜欢神奇的数字,我认为这是一种很好的表示方式,看起来很直观:

#include <string_view>

template <typename T>
constexpr auto type_name() {
  std::string_view name, prefix, suffix;
#ifdef __clang__
  name = __PRETTY_FUNCTION__;
  prefix = "auto type_name() [T = ";
  suffix = "]";
#elif defined(__GNUC__)
  name = __PRETTY_FUNCTION__;
  prefix = "constexpr auto type_name() [with T = ";
  suffix = "]";
#elif defined(_MSC_VER)
  name = __FUNCSIG__;
  prefix = "auto __cdecl type_name<";
  suffix = ">(void)";
#endif
  name.remove_prefix(prefix.size());
  name.remove_suffix(suffix.size());
  return name;
}

演示。