C++ 编译期反射1 - 获取枚举的类型名
注意: 本人是原创, 如若发现雷同,后果自负
有时我们需要获取类型的信息. 类型名, 枚举值的名, 等等. C++ 暂时不支持编译期反射(C++ 23/26会支持), 但是我们可以自己实现, 缺点就是会拖延编译速度.
开发环境:
支持 msvc, clang 和 g++, 需要C++17以上
实现:
// enum_info.hpp
#ifndef ENUM_INFO_HPP
#define ENUM_INFO_HPP
#include <cstddef>
#include <string_view>
#include <type_traits>
namespace enum_info
{
using string_view = std::string_view;
namespace details
{
template <typename Enum_type>
constexpr auto enum_type_name() noexcept
{
// 静态断言, Enum_type 必须是枚举类型
static_assert(std::is_enum_v<Enum_type>, " requires Enum_type == enum");
#if defined(__clang__)
// __PRETTY_FUNCTION__:
// auto enum_info::details::enum_type_name() [Enum_type = B]
constexpr std::size_t prefix = sizeof("auto enum_info::details::enum_type_name() [Enum_type = ") - 1;
constexpr std::size_t suffix = sizeof("]") - 1;
constexpr string_view name{
__PRETTY_FUNCTION__ + prefix, sizeof(__PRETTY_FUNCTION__) - prefix - suffix - 1 };
#elif defined(__GNUC__)
// __PRETTY_FUNCTION__:
// constexpr auto enum_info::details::enum_type_name() [with Enum_type = B]
constexpr std::size_t prefix = sizeof("constexpr auto enum_info::details::enum_type_name() [with Enum_type = ") - 1;
constexpr std::size_t suffix = sizeof("]") - 1;
constexpr string_view name{
__PRETTY_FUNCTION__ + prefix, sizeof(__PRETTY_FUNCTION__) - prefix - suffix - 1 };
#elif defined(_MSC_VER)
// __FUNCSIG__:
// auto __cdecl enum_info::details::enum_type_name<enum main::B>(void) noexcept
constexpr std::size_t prefix = sizeof("auto __cdecl enum_info::details::enum_type_name<enum ") - 1;
constexpr std::size_t suffix = sizeof(">(void) noexcept") - 1;
constexpr string_view name{
__FUNCSIG__ + prefix, sizeof(__FUNCSIG__) - prefix - suffix - 1 };
#endif
return name;
}
} // details
template <typename Enum_type>
inline constexpr string_view enum_type_name_v = details::enum_type_name<Enum_type>();
} // enum_info
#endif // !ENUM_INFO_HPP
原理:
在模板实例化的时候, 编译器将替换__FUNCSIG__
或__PRETTY_FUNCTION__
为函数的信息包括模板参数的信息
- clang 会把上面代码里的
__PRETTY_FUNCTION__
替换成auto enum_info::details::enum_type_name() [Enum_type = B]
- gcc 会把上面代码里的
__PRETTY_FUNCTION__
替换成constexpr auto enum_info::details::enum_type_name() [with Enum_type = B]
- msvc 会把上面代码里的
__FUNCSIG__
替换成auto __cdecl enum_info::details::enum_type_name<enum main::B>(void)
后面只需要偏移就可以获取枚举类型的名称
使用:
// main.cpp
// clang编译器
#include <iostream>
#include "enum_info.hpp"
enum class my_enum
{
};
int main(void)
{
std::cout << enum_info::enum_type_name_v<my_enum> << std::endl;
(void)getchar();
return 0;
}
下期讲获取枚举值的名.