例如:

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

预期的输出:

int

当前回答

您可以使用模板。

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

演示。

基于之前的一些答案,我做出了这个解决方案,它不将__PRETTY_FUNCTION__的结果存储在二进制文件中。它使用静态数组保存类型名称的字符串表示形式。

它需要c++ 23。

#include <iostream>
#include <string_view>
#include <array>

template <typename T>
constexpr auto type_name() {
    auto gen = [] <class R> () constexpr -> std::string_view  {
        return __PRETTY_FUNCTION__;
    };
    constexpr std::string_view search_type = "float";
    constexpr auto search_type_string = gen.template operator()<float>();
    constexpr auto prefix = search_type_string.find(search_type);
    constexpr auto suffix = search_type_string.size() - prefix - search_type.size();
    constexpr auto str = gen.template operator()<T>();
    constexpr int size = str.size() - prefix - suffix;
    constexpr auto static arr = [&]<std::size_t... I>(std::index_sequence<I...>) constexpr {
        return std::array<char, size>{str[prefix + I]...};
    } (std::make_index_sequence<size>{});

    return std::string_view(arr.data(), size);
}

注意,c++的RTTI特性生成的名称是不可移植的。 例如,类

MyNamespace::CMyContainer<int, test_MyNamespace::CMyObject>

将有以下名称:

// MSVC 2003:
class MyNamespace::CMyContainer[int,class test_MyNamespace::CMyObject]
// G++ 4.2:
N8MyNamespace8CMyContainerIiN13test_MyNamespace9CMyObjectEEE

所以不能将此信息用于序列化。但是typeid(a).name()属性仍然可以用于日志/调试目的

非常丑陋,但如果你只想要编译时信息(例如调试):

auto testVar = std::make_tuple(1, 1.0, "abc");
decltype(testVar)::foo= 1;

返回:

Compilation finished with errors:
source.cpp: In function 'int main()':
source.cpp:5:19: error: 'foo' is not a member of 'std::tuple<int, double, const char*>'

你可以上特质课。喜欢的东西:

#include <iostream>
using namespace std;

template <typename T> class type_name {
public:
    static const char *name;
};

#define DECLARE_TYPE_NAME(x) template<> const char *type_name<x>::name = #x;
#define GET_TYPE_NAME(x) (type_name<typeof(x)>::name)

DECLARE_TYPE_NAME(int);

int main()
{
    int a = 12;
    cout << GET_TYPE_NAME(a) << endl;
}

DECLARE_TYPE_NAME定义的存在是为了让您更容易地为所有需要的类型声明这个trait类。

这可能比涉及typeid的解决方案更有用,因为您可以控制输出。例如,在我的编译器上使用typeid For long long会给出“x”。