在 C++ 20 中
您可以使用std::source_location
其静态方法所在::current
的标准consteval
,您可以在编译时使用它,然后您可以获得该function_name
方法。
template <typename T>
consteval auto func_name() {
const auto& loc = std::source_location::current();
return loc.function_name();
}
template <typename T>
consteval std::string_view type_of_impl_() {
constexpr std::string_view func_name_ = func_name<T>();
// since func_name_ is 'consteval auto func_name() [with T = ...]'
// we can simply get the subrange
// because the position after the equal will never change since
// the same function name is used
// another notice: these magic numbers will not work on MSVC
return {func_name_.begin() + 37, func_name.end() - 1};
}
template <typename T>
constexpr auto type_of(T&& arg) {
return type_of_impl_<decltype(arg)>();
}
template <typename T>
constexpr auto type_of() {
return type_of_impl_<T>();
}
注意:源位置对象的函数名称可能因编译器而异,__PRETTY_FUNCTION__
如果您的编译器尚不支持源位置库,您可以使用宏或任何其他相关宏。
用法:
int x = 4;
// type_of also preserves value category and const-qualifiers
// note: it returns std::string_view
type_of(3); // int&&
type_of(x); // int&
type_of(std::as_const(x)); // const int&
type_of(std::move(x)); // int&&
type_of(const_cast<const int&&>(x)); // const int&&
struct del { del() = delete; };
type_of<del>(); // main()::del (if inside main function)
// type_of(del{}); -- error
type_of<int>(); // int
type_of<const int&>(); // const int&
type_of<std::string_view>(); // std::basic_string_view<char>
type_of([]{}); // main()::<lambda()>&&
type_of<decltype([]{})>(); // main()::<lambda()>
type_of<std::make_index_sequence<3>>(); // std::integer_sequence<long unsigned int, 0, 1, 2>
// let's assume this class template is defined outside main function:
template <auto X> struct hello {};
type_of<hello<1>>(); // hello<1>
type_of<hello<3.14f>>(); // hello<3.1400001e+0f>
// also this:
struct point { int x, y; };
type_of<hello<point{.x = 1, .y = 2}>>() // hello<point{1, 2}>
使用这个type_of
而不是拆解的优势typeid(...).name()
:
(另注:我没有测试其他编译器的能力,所以我只保证GCC)
- 您可以在编译时检查该值,这样
static_assert(type_of(4.0) == "double&&")
是有效的。
- 没有运行时开销。
- 该操作可以在运行时或编译时完成(取决于给出的参数是否可用于常量表达式)。
- 它保留了 cv-ref 特征(、
const
和volatile
)。&
&&
- 您也可以使用模板参数,以防万一类型的构造函数被删除并在没有 cv-ref 特征的情况下进行测试。