Wip v0.10.0 (#28)
This commit is contained in:
parent
308bbf9c68
commit
6fa49cca4b
9 changed files with 916 additions and 621 deletions
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.8)
|
||||
|
||||
project(nameof VERSION "0.9.4" LANGUAGES CXX)
|
||||
project(nameof VERSION "0.9.5" LANGUAGES CXX)
|
||||
|
||||
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
||||
set(IS_TOPLEVEL_PROJECT TRUE)
|
||||
|
@ -10,6 +10,7 @@ endif()
|
|||
|
||||
option(NAMEOF_OPT_BUILD_EXAMPLES "Build nameof examples" ${IS_TOPLEVEL_PROJECT})
|
||||
option(NAMEOF_OPT_BUILD_TESTS "Build and perform nameof tests" ${IS_TOPLEVEL_PROJECT})
|
||||
option(NAMEOF_OPT_INSTALL "Generate and install nameof target" ${IS_TOPLEVEL_PROJECT})
|
||||
|
||||
if(NAMEOF_OPT_BUILD_EXAMPLES)
|
||||
add_subdirectory(example)
|
||||
|
@ -33,18 +34,21 @@ write_basic_package_version_file(${PROJECT_NAME}ConfigVersion.cmake
|
|||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
if(NAMEOF_OPT_INSTALL)
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}Config)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
|
||||
DESTINATION lib/cmake/${PROJECT_NAME})
|
||||
|
||||
install(EXPORT ${PROJECT_NAME}Config
|
||||
install(EXPORT ${PROJECT_NAME}Config
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION lib/cmake/${PROJECT_NAME})
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
DESTINATION .)
|
||||
|
||||
export(EXPORT ${PROJECT_NAME}Config
|
||||
export(EXPORT ${PROJECT_NAME}Config
|
||||
NAMESPACE ${PROJECT_NAME}::)
|
||||
endif()
|
||||
|
||||
|
|
32
README.md
32
README.md
|
@ -8,7 +8,7 @@
|
|||
```
|
||||
|
||||
[![Github releases](https://img.shields.io/github/release/Neargye/nameof.svg)](https://github.com/Neargye/nameof/releases)
|
||||
[![Conan package](https://img.shields.io/badge/Conan-package-blueviolet)](https://conan.io/center/nameof/0.9.4)
|
||||
[![Conan package](https://img.shields.io/badge/Conan-package-blueviolet)](https://conan.io/center/nameof)
|
||||
[![Vcpkg package](https://img.shields.io/badge/Vcpkg-package-blueviolet)](https://github.com/microsoft/vcpkg/tree/master/ports/nameof)
|
||||
[![License](https://img.shields.io/github/license/Neargye/nameof.svg)](LICENSE)
|
||||
[![Build status](https://travis-ci.org/Neargye/nameof.svg?branch=master)](https://travis-ci.org/Neargye/nameof)
|
||||
|
@ -86,19 +86,29 @@ Header-only C++17 library provides nameof macros and functions to simply obtain
|
|||
* Nameof type
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
T var = 42;
|
||||
const my::detail::SomeClass<int>& var_ref = var;
|
||||
// Name of variable type.
|
||||
NAMEOF_TYPE_EXPR(var) -> "int"
|
||||
NAMEOF_FULL_TYPE_EXPR(var) -> "const int&"
|
||||
nameof::nameof_type<decltype(var)>() -> "int"
|
||||
nameof::nameof_full_type<decltype(var)>() -> "const int&"
|
||||
NAMEOF_TYPE_EXPR(var_ref) -> "my::detail::SomeClass<int>"
|
||||
nameof::nameof_type<decltype(var_ref)>() -> "my::detail::SomeClass<int>"
|
||||
NAMEOF_FULL_TYPE_EXPR(var_ref) -> "const my::detail::SomeClass<int>&"
|
||||
nameof::nameof_full_type<decltype(var_ref)>() -> "const my::detail::SomeClass<int>&"
|
||||
NAMEOF_SHORT_TYPE_EXPR(var_ref) -> "SomeClass"
|
||||
nameof::nameof_short_type<decltype(var_ref)>() -> "SomeClass"
|
||||
|
||||
using T = const my::detail::SomeClass<int>&;
|
||||
// Name of type.
|
||||
NAMEOF_TYPE(T) -> "int"
|
||||
NAMEOF_FULL_TYPE(T) -> "const int&"
|
||||
nameof::nameof_type<T>() -> "int"
|
||||
nameof::nameof_full_type<T>() -> "const int&"
|
||||
NAMEOF_TYPE(T) ->"my::detail::SomeClass<int>"
|
||||
nameof::nameof_type<T>() -> "my::detail::SomeClass<int>"
|
||||
NAMEOF_FULL_TYPE(T) -> "const my::detail::SomeClass<int>&"
|
||||
nameof::nameof_full_type<T>() -> "const my::detail::SomeClass<int>&"
|
||||
NAMEOF_SHORT_TYPE(T) -> "SomeClass"
|
||||
nameof::nameof_short_type<T>() -> "SomeClass"
|
||||
|
||||
my::detail::Base* ptr = new my::detail::Derived();
|
||||
// Name of type, using rtti.
|
||||
NAMEOF_TYPE_RTTI(*ptr) -> "my::detail::Derived"
|
||||
NAMEOF_FULL_TYPE_RTTI(*ptr) -> "volatile const my::detail::Derived&"
|
||||
NAMEOF_SHORT_TYPE_RTTI(*ptr) -> "Derived"
|
||||
```
|
||||
|
||||
* Compile-time
|
||||
|
|
|
@ -6,23 +6,24 @@
|
|||
|
||||
## Nameof Type
|
||||
|
||||
* To check is nameof type supported compiler use macro `NAMEOF_TYPE_SUPPORTED` or constexpr constant `nameof::is_nameof_type_supported`.
|
||||
|
||||
* This library uses a compiler-specific hack (based on `__PRETTY_FUNCTION__` / `__FUNCSIG__`), which works on Clang >= 5, MSVC >= 15.3 and GCC >= 7.
|
||||
|
||||
* Nameof type returns compiler-specific type name.
|
||||
* nameof_type and nameof_type_rtti returns compiler-specific type name.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
* To check is nameof_type supported compiler use macro `NAMEOF_TYPE_SUPPORTED` or constexpr constant `nameof::is_nameof_type_supported`.</br>
|
||||
If nameof_type used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check is nameof_type_rtti supported compiler use macro `NAMEOF_TYPE_RTTI_SUPPORTED` or constexpr constant `nameof::is_nameof_type_rtti_supported`.</br>
|
||||
If nameof_type used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
## Nameof Enum
|
||||
|
||||
* Do not use [nameof](https://github.com/Neargye/nameof) and [magic_enum](https://github.com/Neargye/magic_enum) in the same project to get enum name.
|
||||
|
||||
* To check is nameof enum supported compiler use macro `NAMEOF_ENUM_SUPPORTED` or constexpr constant `nameof::is_nameof_enum_supported`.
|
||||
|
||||
* This library uses a compiler-specific hack (based on `__PRETTY_FUNCTION__` / `__FUNCSIG__`), which works on Clang >= 5, MSVC >= 15.3 and GCC >= 9.
|
||||
|
||||
* Enum can't reflect if the enum is a forward declaration.
|
||||
* Do not use [nameof](https://github.com/Neargye/nameof) and [magic_enum](https://github.com/Neargye/magic_enum) in the same project to get enum name.
|
||||
|
||||
* To check is nameof_enum supported compiler use macro `NAMEOF_ENUM_SUPPORTED` or constexpr constant `nameof::is_nameof_enum_supported`.</br>
|
||||
If nameof_enum used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_ENUM_NO_CHECK_SUPPORT`.
|
||||
|
||||
* Enum value must be in range `[NAMEOF_ENUM_RANGE_MIN, NAMEOF_ENUM_RANGE_MAX]`.
|
||||
|
||||
|
@ -40,74 +41,22 @@
|
|||
#include <nameof.hpp>
|
||||
```
|
||||
|
||||
* If need another range for specific enum type, add specialization `enum_range` for necessary enum type. Specialization of `enum_range` must be injected in `namespace nameof`.
|
||||
* If need another range for specific enum type, add specialization `enum_range` for necessary enum type. Specialization of `enum_range` must be injected in `namespace nameof::customize`.
|
||||
|
||||
```cpp
|
||||
#include <nameof.hpp>
|
||||
|
||||
enum class number { one = 100, two = 200, three = 300 };
|
||||
|
||||
namespace nameof {
|
||||
template <>
|
||||
struct enum_range<number> {
|
||||
struct nameof::customize::enum_range<number> {
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
};
|
||||
} // namespace nameof
|
||||
```
|
||||
|
||||
* Nameof enum won't work if a value is aliased, work with enum-aliases is compiler-implementation-defined.
|
||||
* Won't work if a value is aliased, work with enum-aliases is compiler-implementation-defined.
|
||||
|
||||
```cpp
|
||||
enum ShapeKind {
|
||||
ConvexBegin = 0,
|
||||
Box = 0, // Won't work.
|
||||
Sphere = 1,
|
||||
ConvexEnd = 2,
|
||||
Donut = 2, // Won't work too.
|
||||
Banana = 3,
|
||||
COUNT = 4,
|
||||
};
|
||||
// nameof::nameof_enum(ShapeKind::Box) -> "ConvexBegin" or ""
|
||||
// NAMEOF_ENUM(ShapeKind::Box) -> "ConvexBegin" or ""
|
||||
```
|
||||
|
||||
One of the possible workaround the issue:
|
||||
|
||||
```cpp
|
||||
enum ShapeKind {
|
||||
// Convex shapes, see ConvexBegin and ConvexEnd below.
|
||||
Box = 0,
|
||||
Sphere = 1,
|
||||
|
||||
// Non-convex shapes.
|
||||
Donut = 2,
|
||||
Banana = 3,
|
||||
|
||||
COUNT = Banana + 1,
|
||||
|
||||
// Non-reflected aliases.
|
||||
ConvexBegin = Box,
|
||||
ConvexEnd = Sphere + 1,
|
||||
};
|
||||
// nameof::nameof_enum(ShapeKind::Box) -> "Box"
|
||||
// NAMEOF_ENUM(ShapeKind::Box) -> "Box"
|
||||
|
||||
// Non-reflected aliases.
|
||||
// nameof::nameof_enum(ShapeKind::ConvexBegin) -> "Box"
|
||||
// NAMEOF_ENUM(ShapeKind::ConvexBegin) -> "Box"
|
||||
```
|
||||
|
||||
* If you hit a message like this:
|
||||
|
||||
```text
|
||||
[...]
|
||||
note: constexpr evaluation hit maximum step limit; possible infinite loop?
|
||||
```
|
||||
|
||||
Change the limit for the number of constexpr evaluated:
|
||||
* MSVC `/constexpr:depthN`, `/constexpr:stepsN` <https://docs.microsoft.com/en-us/cpp/build/reference/constexpr-control-constexpr-evaluation>
|
||||
* Clang `-fconstexpr-depth=N`, `-fconstexpr-steps=N` <https://clang.llvm.org/docs/UsersManual.html#controlling-implementation-limits>
|
||||
* GCC `-fconstexpr-depth=N`, `-fconstexpr-loop-limit=N`, `-fconstexpr-ops-limit=N` <https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/C_002b_002b-Dialect-Options.html>
|
||||
* Won't work if the enum is a forward declaration.
|
||||
|
||||
* Intellisense Visual Studio may have some problems analyzing `nameof`.
|
||||
|
|
265
doc/reference.md
265
doc/reference.md
|
@ -1,38 +1,39 @@
|
|||
# Reference
|
||||
|
||||
* [`NAMEOF` macro that obtains simple (unqualified) string name of variable, function, macro.](#nameof)
|
||||
* [`NAMEOF_FULL` macro that obtains simple (unqualified) full (with template suffix) string name of variable, function, macro.](#nameof_full)
|
||||
* [`NAMEOF_RAW` macro that obtains raw string name of variable, function, macro.](#nameof_raw)
|
||||
* [`nameof_enum` function that obtains simple (unqualified) string name of enum variable.](#nameof_enum)
|
||||
* [`NAMEOF_ENUM` macro that obtains simple (unqualified) string name of enum variable.](#nameof_enum-1)
|
||||
* [`NAMEOF_ENUM_CONST` macro that obtains simple (unqualified) string name of static storage enum variable.](#nameof_enum_const)
|
||||
* [`nameof_enum_flag` function that obtains simple (unqualified) string name of enum variable.](#nameof_enum_flag)
|
||||
* [`NAMEOF_ENUM_FLAG` function that obtains simple (unqualified) string name of enum variable.](#nameof_enum_flag-1)
|
||||
* [`nameof_type` function that obtains string name of type, reference and cv-qualifiers are ignored.](#nameof_type)
|
||||
* [`nameof_full_type` function that obtains string name of full type, with reference and cv-qualifiers.](#nameof_full_type)
|
||||
* [`NAMEOF_TYPE` macro that obtains string name of type, reference and cv-qualifiers are ignored.](#nameof_type-1)
|
||||
* [`NAMEOF_FULL_TYPE` macro that obtains string name of full type, with reference and cv-qualifiers.](#nameof_full_type-1)
|
||||
* [`NAMEOF_TYPE_EXPR` macro that obtains string name type of expression, reference and cv-qualifiers are ignored.](#nameof_type_expr)
|
||||
* [`NAMEOF_FULL_TYPE_EXPR` macro that obtains string name full type of expression, with reference and cv-qualifiers.](#nameof_full_type_expr)
|
||||
* [`NAMEOF_TYPE_RTTI` macro that obtains string name type, using RTTI.](#nameof_type_rtti)
|
||||
* [`NAMEOF` obtains simple name of variable, function, macro.](#nameof)
|
||||
* [`NAMEOF_FULL` obtains full name of variable, function, macro.](#nameof_full)
|
||||
* [`NAMEOF_RAW` obtains raw name of variable, function, macro.](#nameof_raw)
|
||||
* [`NAMEOF_ENUM` obtains name of enum variable.](#nameof_enum)
|
||||
* [`NAMEOF_ENUM_CONST` obtains name of static storage enum variable.](#nameof_enum_const)
|
||||
* [`NAMEOF_ENUM_FLAG` obtains name of enum-flags variable.](#nameof_enum_flag)
|
||||
* [`NAMEOF_TYPE` obtains type name.](#nameof_type)
|
||||
* [`NAMEOF_FULL_TYPE` obtains full type name.](#nameof_full_type)
|
||||
* [`NAMEOF_SHORT_TYPE` obtains short type name.](#nameof_short_type)
|
||||
* [`NAMEOF_TYPE_EXPR` obtains type name of expression.](#nameof_type_expr)
|
||||
* [`NAMEOF_FULL_TYPE_EXPR` obtains full type name of expression.](#nameof_full_type_expr)
|
||||
* [`NAMEOF_SHORT_TYPE_EXPR` obtains short type name of expression.](#nameof_short_type_expr)
|
||||
* [`NAMEOF_TYPE_RTTI` obtains type name, using RTTI.](#nameof_type_rtti)
|
||||
* [`NAMEOF_FULL_TYPE_RTTI` obtains short type name, using RTTI.](#nameof_full_type_rtti)
|
||||
* [`NAMEOF_SHORT_TYPE_RTTI` obtains short type name, using RTTI.](#nameof_short_type_rtti)
|
||||
|
||||
## Synopsis
|
||||
|
||||
* Before use, read the [limitations](limitations.md) of functionality.
|
||||
|
||||
* All functions `constexpr` and `noexcept`.
|
||||
|
||||
* To check is nameof_type supported compiler use macro `NAMEOF_TYPE_SUPPORTED` or constexpr constant `nameof::is_nameof_type_supported`.</br>
|
||||
If nameof_type used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check is nameof_type_rtti supported compiler use macro `NAMEOF_TYPE_RTTI_SUPPORTED` or constexpr constant `nameof::is_nameof_type_rtti_supported`.</br>
|
||||
If nameof_type used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
|
||||
|
||||
* To check is nameof_enum supported compiler use macro `NAMEOF_ENUM_SUPPORTED` or constexpr constant `nameof::is_nameof_enum_supported`.</br>
|
||||
If nameof_enum used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_ENUM_NO_CHECK_SUPPORT`.
|
||||
|
||||
## `NAMEOF`
|
||||
|
||||
* Macro that obtains simple (unqualified) string name of variable, function, macro.
|
||||
* Obtains simple (unqualified) name of variable, function, macro.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string.
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
|
||||
|
@ -59,9 +60,9 @@
|
|||
|
||||
## `NAMEOF_FULL`
|
||||
|
||||
* Macro that obtains simple (unqualified) full (with template suffix) string name of variable, function, macro.
|
||||
* Obtains simple (unqualified) full (with template suffix) name of variable, function, macro.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string.
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
|
||||
|
@ -77,9 +78,9 @@
|
|||
|
||||
## `NAMEOF_RAW`
|
||||
|
||||
* Macro that obtains raw string name of variable, function, macro.
|
||||
* Obtains raw name of variable, function, macro.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string.
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
|
||||
|
@ -90,55 +91,28 @@
|
|||
NAMEOF_RAW(&some_class::some_method<int>) -> "&some_class::some_method<int>"
|
||||
```
|
||||
|
||||
## `nameof_enum`
|
||||
|
||||
* Function that obtains simple (unqualified) string name of enum variable.
|
||||
|
||||
* Returns `std::string_view`.
|
||||
|
||||
* Enum variable to string.
|
||||
|
||||
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `std::string_view`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
auto color = Color::RED;
|
||||
nameof::nameof_enum(color) -> "RED"
|
||||
```
|
||||
|
||||
* Static storage enum variable to string.
|
||||
|
||||
* This version is much lighter on the compile times and is not restricted to the enum_range [limitation](limitations.md#nameof-enum).
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Enum value does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
nameof::nameof_enum<Color::GREEN>() -> "GREEN"
|
||||
```
|
||||
|
||||
## `NAMEOF_ENUM`
|
||||
|
||||
* Macro that obtains simple (unqualified) string name of enum variable.
|
||||
* Obtains simple (unqualified) name of enum variable.
|
||||
|
||||
* Returns `std::string_view`.
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `std::string_view`.
|
||||
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `string_view`, in debug occurs assert.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
auto color = Color::RED;
|
||||
NAMEOF_ENUM(color) -> "RED"
|
||||
nameof::nameof_enum(color) -> "RED"
|
||||
```
|
||||
|
||||
## `NAMEOF_ENUM_CONST`
|
||||
|
||||
* Macro that obtains simple (unqualified) string name of static storage enum variable.
|
||||
* Obtains simple (unqualified) name of static storage enum variable.
|
||||
|
||||
* Returns `std::string_view`.
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* This version is much lighter on the compile times and is not restricted to the enum_range [limitation](limitations.md#nameof-enum).
|
||||
|
||||
|
@ -148,133 +122,102 @@
|
|||
|
||||
```cpp
|
||||
NAMEOF_ENUM_CONST(Color::GREEN) -> "GREEN"
|
||||
```
|
||||
|
||||
## `nameof_enum_flag`
|
||||
|
||||
* Function that obtains simple (unqualified) string name of enum flag variable.
|
||||
|
||||
* Returns `std::string`.
|
||||
|
||||
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `std::string`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
enum class AnimalFlags { HasClaws = 1 << 0, CanFly = 1 << 1, EatsFish = 1 << 2, Endangered = 1 << 3 };
|
||||
auto flag = AnimalFlags::Endangered;
|
||||
nameof_enum_flag(flag) -> "Endangered"
|
||||
flag = AnimalFlags::Endangered | AnimalFlags::CanFly;
|
||||
nameof_enum_flag(flag) -> "CanFly|Endangered"
|
||||
nameof_enum_flag(flag) -> "HasClaws|CanFly"
|
||||
|
||||
nameof_enum(HasClaws | CanFly) -> ""
|
||||
nameof::nameof_enum<Color::GREEN>() -> "GREEN"
|
||||
```
|
||||
|
||||
## `NAMEOF_ENUM_FLAG`
|
||||
|
||||
* Macro that obtains simple (unqualified) string name of enum flag variable.
|
||||
* Obtains simple (unqualified) name of enum flag variable.
|
||||
|
||||
* Returns `std::string`.
|
||||
* Returns `string`.
|
||||
|
||||
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `std::string`.
|
||||
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `string`, in debug occurs assert.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
enum class AnimalFlags { HasClaws = 1 << 0, CanFly = 1 << 1, EatsFish = 1 << 2, Endangered = 1 << 3 };
|
||||
auto flag = AnimalFlags::Endangered;
|
||||
|
||||
NAMEOF_ENUM_FLAG(flag) -> "Endangered"
|
||||
flag = AnimalFlags::Endangered | AnimalFlags::CanFly;
|
||||
nameof_enum_flag(flag) -> "Endangered"
|
||||
|
||||
flag = AnimalFlags::CanFly | AnimalFlags::Endangered;
|
||||
NAMEOF_ENUM_FLAG(flag) -> "CanFly|Endangered"
|
||||
NAMEOF_ENUM_FLAG(flag) -> "HasClaws|CanFly"
|
||||
nameof_enum_flag(flag) -> "CanFly|Endangered"
|
||||
|
||||
NAMEOF_ENUM(HasClaws | CanFly) -> ""
|
||||
```
|
||||
|
||||
## `nameof_type`
|
||||
|
||||
* Function that obtains string name of type, reference and cv-qualifiers are ignored.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string.
|
||||
|
||||
* In all cases, reference and cv-qualifiers are ignored by `nameof_type` (that is, `nameof_type<const T&>() == nameof_type<T>()`).
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
nameof::nameof_type<T>() -> "int"
|
||||
```
|
||||
|
||||
## `nameof_full_type`
|
||||
|
||||
* Function that obtains string name of full type, with reference and cv-qualifiers.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
nameof::nameof_full_type<T>() -> "const int&"
|
||||
nameof_enum(HasClaws | CanFly) -> ""
|
||||
```
|
||||
|
||||
## `NAMEOF_TYPE`
|
||||
|
||||
* Macro that obtains string name of type, reference and cv-qualifiers are ignored.
|
||||
* Obtains type name, reference and cv-qualifiers are ignored.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string.
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* In all cases, reference and cv-qualifiers are ignored by `NAMEOF_TYPE` (that is, `NAMEOF_TYPE(const T&) == NAMEOF_TYPE(T)`).
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
NAMEOF_TYPE(T) -> "int"
|
||||
nameof::nameof_type<T>() -> "int"
|
||||
```
|
||||
|
||||
## `NAMEOF_FULL_TYPE`
|
||||
|
||||
* Macro that obtains string name of full type, with reference and cv-qualifiers.
|
||||
* Obtains full type name, with reference and cv-qualifiers.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string.
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const int&;
|
||||
NAMEOF_TYPE(T) -> "const int&"
|
||||
nameof::nameof_full_type<T>() -> "const int&"
|
||||
```
|
||||
|
||||
## `NAMEOF_SHORT_TYPE`
|
||||
|
||||
* Obtains short type name.
|
||||
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
using T = const my::detail::SomeClass<int>&;
|
||||
NAMEOF_SHORT_TYPE(T) -> "SomeClass"
|
||||
nameof::nameof_short_type<T>() -> "SomeClass"
|
||||
```
|
||||
|
||||
## `NAMEOF_TYPE_EXPR`
|
||||
|
||||
* Macro that obtains string name type of expression, reference and cv-qualifiers are ignored.
|
||||
* Obtains string name type of expression, reference and cv-qualifiers are ignored.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string.
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns returns compiler-specific type name.
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* In all cases, reference and cv-qualifiers are ignored.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
|
@ -282,17 +225,18 @@
|
|||
using T = const int&;
|
||||
T var = 42;
|
||||
NAMEOF_TYPE_EXPR(var) -> "int"
|
||||
nameof::nameof_type<decltype(var)>() -> "int"
|
||||
```
|
||||
|
||||
## `NAMEOF_FULL_TYPE_EXPR`
|
||||
|
||||
* Macro that obtains string name full type of expression, with reference and cv-qualifiers.
|
||||
* Obtains full type name of expression, with reference and cv-qualifiers.
|
||||
|
||||
* Returns `nameof::cstring` - constexpr implementation of an string.
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
|
@ -300,21 +244,62 @@
|
|||
using T = const int&;
|
||||
T var = 42;
|
||||
NAMEOF_FULL_TYPE_EXPR(var) -> "const int&"
|
||||
nameof::nameof_full_type<decltype(var)>() -> "const int&"
|
||||
```
|
||||
|
||||
## `NAMEOF_TYPE_RTTI`
|
||||
## `NAMEOF_SHORT_TYPE_EXPR`
|
||||
|
||||
* Macro that obtains string name of type, using RTTI.
|
||||
* Obtains short type name of expression.
|
||||
|
||||
* Returns demangled RTTI type name.
|
||||
* Returns `string_view`. Marked `constexpr` and `noexcept`.
|
||||
|
||||
* Returns compiler-specific type name.
|
||||
|
||||
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
struct Base { virtual void foo() {} };
|
||||
struct Derived : Base {};
|
||||
|
||||
Base* ptr = new Derived();
|
||||
NAMEOF_TYPE_RTTI(ptr) -> "Base *"
|
||||
NAMEOF_TYPE_RTTI(*ptr) -> "Derived"
|
||||
const my::detail::SomeClass<int> var;
|
||||
NAMEOF_SHORT_TYPE_EXPR(var) -> "SomeClass"
|
||||
nameof::nameof_short_type<decltype(var)>() -> "SomeClass"
|
||||
```
|
||||
|
||||
## `NAMEOF_TYPE_RTTI`
|
||||
|
||||
* Obtains type name, using RTTI.
|
||||
|
||||
* Returns `string`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
volatile const my::detail::Base* ptr = new my::detail::Derived();
|
||||
NAMEOF_TYPE_RTTI(*ptr) -> "my::detail::Derived"
|
||||
```
|
||||
|
||||
## `NAMEOF_FULL_TYPE_RTTI`
|
||||
|
||||
* Obtains full type name, using RTTI.
|
||||
|
||||
* Returns `string`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
volatile const my::detail::Base* ptr = new my::detail::Derived();
|
||||
NAMEOF_FULL_TYPE_RTTI(cv_ref) -> "volatile const my::detail::Derived&"
|
||||
``
|
||||
|
||||
## `NAMEOF_SHORT_TYPE_RTTI`
|
||||
|
||||
* Obtains short type name, using RTTI.
|
||||
|
||||
* Returns `string`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
volatile const my::detail::Base* ptr = new my::detail::Derived();
|
||||
NAMEOF_SHORT_TYPE_RTTI(*ptr) -> "Derived"
|
||||
```
|
||||
|
|
|
@ -9,8 +9,13 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|||
endif()
|
||||
endif()
|
||||
|
||||
add_executable(example example.cpp)
|
||||
set_target_properties(example PROPERTIES CXX_EXTENSIONS OFF)
|
||||
target_compile_features(example PRIVATE cxx_std_17)
|
||||
target_compile_options(example PRIVATE ${OPTIONS})
|
||||
target_link_libraries(example PRIVATE ${CMAKE_PROJECT_NAME})
|
||||
function(make_example target)
|
||||
add_executable(${target} ${target}.cpp)
|
||||
set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF)
|
||||
target_compile_features(${target} PRIVATE cxx_std_17)
|
||||
target_compile_options(${target} PRIVATE ${OPTIONS})
|
||||
target_link_libraries(${target} PRIVATE ${CMAKE_PROJECT_NAME})
|
||||
endfunction()
|
||||
|
||||
make_example(example)
|
||||
make_example(example_custom_name)
|
||||
|
|
|
@ -178,8 +178,8 @@ int main() {
|
|||
#if defined(NAMEOF_TYPE_RTTI_SUPPORTED)
|
||||
// Nameof type using RTTI.
|
||||
Base* ptr = new Derived();
|
||||
std::cout << NAMEOF_TYPE_RTTI(ptr) << std::endl; // "Base *"
|
||||
std::cout << NAMEOF_TYPE_RTTI(*ptr) << std::endl; // "Derived"
|
||||
std::cout << NAMEOF_TYPE_RTTI(ptr) << std::endl; // 'Base *'
|
||||
std::cout << NAMEOF_TYPE_RTTI(*ptr) << std::endl; // 'Derived'
|
||||
#endif
|
||||
|
||||
// Some more complex example.
|
||||
|
|
93
example/example_custom_name.cpp
Normal file
93
example/example_custom_name.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <nameof.hpp>
|
||||
|
||||
enum class Color : int { RED = -10, BLUE = 0, GREEN = 10 };
|
||||
enum class Numbers : int { One, Two, Three };
|
||||
|
||||
#if defined(NAMEOF_ENUM_SUPPORTED)
|
||||
// Сustom definitions of names for enum.
|
||||
// Specialization of `enum_name` must be injected in `namespace nameof::customize`.
|
||||
template <>
|
||||
constexpr std::string_view nameof::customize::enum_name<Color>(Color value) noexcept {
|
||||
switch (value) {
|
||||
case Color::RED:
|
||||
return "the red color";
|
||||
case Color::BLUE:
|
||||
return "The BLUE";
|
||||
case Color::GREEN:
|
||||
return {}; // Empty string for default value.
|
||||
}
|
||||
return {}; // Empty string for unknow value.
|
||||
}
|
||||
|
||||
// Сustom definitions of names for enum.
|
||||
// Specialization of `enum_name` must be injected in `namespace nameof::customize`.
|
||||
template <>
|
||||
constexpr std::string_view nameof::customize::enum_name<Numbers>(Numbers value) noexcept {
|
||||
switch (value) {
|
||||
case Numbers::One:
|
||||
return "the one";
|
||||
default:
|
||||
return {}; // Empty string for default or unknow value.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Сustom definitions of names for type.
|
||||
// Specialization of `type_name` must be injected in `namespace nameof::customize`.
|
||||
template <>
|
||||
constexpr std::string_view nameof::customize::type_name<Color>() noexcept {
|
||||
return "The Color";
|
||||
}
|
||||
|
||||
class a1_test {};
|
||||
class a2_test {};
|
||||
|
||||
// Сustom definitions of names for type.
|
||||
// Specialization of `type_name` must be injected in `namespace nameof::customize`.
|
||||
template <>
|
||||
constexpr std::string_view nameof::customize::type_name<a1_test>() noexcept {
|
||||
return "Animal";
|
||||
}
|
||||
|
||||
int main() {
|
||||
#if defined(NAMEOF_ENUM_SUPPORTED)
|
||||
std::cout << nameof::nameof_enum(Color::RED) << std::endl; // 'the red color'
|
||||
std::cout << nameof::nameof_enum(Color::BLUE) << std::endl; // 'The BLUE'
|
||||
std::cout << nameof::nameof_enum(Color::GREEN) << std::endl; // 'GREEN'
|
||||
|
||||
std::cout << nameof::nameof_enum(Numbers::One) << std::endl; // 'the one'
|
||||
std::cout << nameof::nameof_enum(Numbers::Two) << std::endl; // 'Two'
|
||||
std::cout << nameof::nameof_enum(Numbers::Three) << std::endl; // 'Three'
|
||||
#endif
|
||||
|
||||
std::cout << nameof::nameof_type<Color>() << std::endl; // 'The Color'
|
||||
std::cout << nameof::nameof_type<Numbers>() << std::endl; // 'Numbers'
|
||||
std::cout << nameof::nameof_type<a1_test>() << std::endl; // 'Animal'
|
||||
std::cout << nameof::nameof_type<a2_test>() << std::endl; // 'a2_test'
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
// | |\ | (_| | | | | | | __/ (_) | | | |____|_| |_|
|
||||
// |_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____|
|
||||
// https://github.com/Neargye/nameof
|
||||
// version 0.9.4
|
||||
// version 0.9.5
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
@ -34,7 +34,7 @@
|
|||
|
||||
#define NAMEOF_VERSION_MAJOR 0
|
||||
#define NAMEOF_VERSION_MINOR 9
|
||||
#define NAMEOF_VERSION_PATCH 4
|
||||
#define NAMEOF_VERSION_PATCH 5
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
@ -118,15 +118,31 @@
|
|||
|
||||
namespace nameof {
|
||||
|
||||
// If need another string_view type, define the macro NAMEOF_USING_ALIAS_STRING_VIEW.
|
||||
#if defined(NAMEOF_USING_ALIAS_STRING_VIEW)
|
||||
NAMEOF_USING_ALIAS_STRING_VIEW
|
||||
#else
|
||||
using string_view = std::string_view;
|
||||
#endif
|
||||
|
||||
// If need another string type, define the macro NAMEOF_USING_ALIAS_STRING.
|
||||
#if defined(NAMEOF_USING_ALIAS_STRING)
|
||||
NAMEOF_USING_ALIAS_STRING
|
||||
#else
|
||||
using string = std::string;
|
||||
#endif
|
||||
|
||||
namespace customize {
|
||||
|
||||
// Enum value must be in range [NAMEOF_ENUM_RANGE_MIN, NAMEOF_ENUM_RANGE_MAX]. By default NAMEOF_ENUM_RANGE_MIN = -128, NAMEOF_ENUM_RANGE_MAX = 128.
|
||||
// If need another range for all enum types by default, redefine the macro NAMEOF_ENUM_RANGE_MIN and NAMEOF_ENUM_RANGE_MAX.
|
||||
// If need another range for specific enum type, add specialization enum_range for necessary enum type.
|
||||
template <typename E>
|
||||
struct enum_range {
|
||||
static_assert(std::is_enum_v<E>, "nameof::enum_range requires enum type.");
|
||||
static_assert(std::is_enum_v<E>, "nameof::customize::enum_range requires enum type.");
|
||||
inline static constexpr int min = NAMEOF_ENUM_RANGE_MIN;
|
||||
inline static constexpr int max = NAMEOF_ENUM_RANGE_MAX;
|
||||
static_assert(max > min, "nameof::enum_range requires max > min.");
|
||||
static_assert(max > min, "nameof::customize::enum_range requires max > min.");
|
||||
};
|
||||
|
||||
static_assert(NAMEOF_ENUM_RANGE_MIN <= 0, "NAMEOF_ENUM_RANGE_MIN must be less or equals than 0.");
|
||||
|
@ -137,15 +153,24 @@ static_assert(NAMEOF_ENUM_RANGE_MAX < (std::numeric_limits<std::int16_t>::max)()
|
|||
|
||||
static_assert(NAMEOF_ENUM_RANGE_MAX > NAMEOF_ENUM_RANGE_MIN, "NAMEOF_ENUM_RANGE_MAX must be greater than NAMEOF_ENUM_RANGE_MIN.");
|
||||
|
||||
// If need cunstom names for enum, add specialization enum_name for necessary enum type.
|
||||
template <typename E>
|
||||
constexpr string_view enum_name(E) noexcept {
|
||||
static_assert(std::is_enum_v<E>, "nameof::customize::enum_name requires enum type.");
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// If need cunstom name for type, add specialization type_name for necessary type.
|
||||
template <typename T>
|
||||
constexpr string_view type_name() noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace nameof::customize
|
||||
|
||||
template <std::size_t N>
|
||||
class [[nodiscard]] cstring {
|
||||
static_assert(N > 0, "nameof::cstring requires size greater than 0.");
|
||||
|
||||
std::array<char, N + 1> chars_;
|
||||
|
||||
template <std::size_t... I>
|
||||
constexpr cstring(std::string_view str, std::index_sequence<I...>) noexcept : chars_{{str[I]..., '\0'}} {}
|
||||
|
||||
public:
|
||||
using value_type = const char;
|
||||
using size_type = std::size_t;
|
||||
|
@ -161,8 +186,8 @@ class [[nodiscard]] cstring {
|
|||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
constexpr explicit cstring(std::string_view str) noexcept : cstring{str, std::make_index_sequence<N>{}} {
|
||||
assert(str.size() == N);
|
||||
constexpr explicit cstring(string_view str) noexcept : cstring{str, std::make_index_sequence<N>{}} {
|
||||
assert(str.size() > 0 && str.size() == N);
|
||||
}
|
||||
|
||||
constexpr cstring() = delete;
|
||||
|
@ -209,80 +234,84 @@ class [[nodiscard]] cstring {
|
|||
|
||||
[[nodiscard]] constexpr bool empty() const noexcept { return false; }
|
||||
|
||||
[[nodiscard]] constexpr int compare(std::string_view str) const noexcept {
|
||||
return std::string_view{data(), size()}.compare(str);
|
||||
[[nodiscard]] constexpr int compare(string_view str) const noexcept {
|
||||
return string_view{data(), size()}.compare(str);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const char* c_str() const noexcept { return data(); }
|
||||
|
||||
template <typename Char = char, typename Traits = std::char_traits<Char>, typename Allocator = std::allocator<Char>>
|
||||
[[nodiscard]] std::basic_string<Char, Traits, Allocator> str() const { return {begin(), end()}; }
|
||||
[[nodiscard]] string str() const { return {begin(), end()}; }
|
||||
|
||||
[[nodiscard]] constexpr operator std::string_view() const noexcept { return {data(), size()}; }
|
||||
[[nodiscard]] constexpr operator string_view() const noexcept { return {data(), size()}; }
|
||||
|
||||
[[nodiscard]] constexpr explicit operator const char*() const noexcept { return data(); }
|
||||
[[nodiscard]] constexpr explicit operator const_pointer() const noexcept { return data(); }
|
||||
|
||||
template <typename Char = char, typename Traits = std::char_traits<Char>, typename Allocator = std::allocator<Char>>
|
||||
[[nodiscard]] explicit operator std::basic_string<Char, Traits, Allocator>() const { return {begin(), end()}; }
|
||||
[[nodiscard]] explicit operator string() const { return {begin(), end()}; }
|
||||
|
||||
private:
|
||||
template <std::size_t... I>
|
||||
constexpr cstring(string_view str, std::index_sequence<I...>) noexcept : chars_{{str[I]..., '\0'}} {}
|
||||
|
||||
std::array<char, N + 1> chars_;
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator==(const cstring<N>& lhs, std::string_view rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator==(const cstring<N>& lhs, string_view rhs) noexcept {
|
||||
return lhs.compare(rhs) == 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator==(std::string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator==(string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
return lhs.compare(rhs) == 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator!=(const cstring<N>& lhs, std::string_view rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator!=(const cstring<N>& lhs, string_view rhs) noexcept {
|
||||
return lhs.compare(rhs) != 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator!=(std::string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator!=(string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
return lhs.compare(rhs) != 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator>(const cstring<N>& lhs, std::string_view rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator>(const cstring<N>& lhs, string_view rhs) noexcept {
|
||||
return lhs.compare(rhs) > 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator>(std::string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator>(string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
return lhs.compare(rhs) > 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator>=(const cstring<N>& lhs, std::string_view rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator>=(const cstring<N>& lhs, string_view rhs) noexcept {
|
||||
return lhs.compare(rhs) >= 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator>=(std::string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator>=(string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
return lhs.compare(rhs) >= 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator<(const cstring<N>& lhs, std::string_view rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator<(const cstring<N>& lhs, string_view rhs) noexcept {
|
||||
return lhs.compare(rhs) < 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator<(std::string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator<(string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
return lhs.compare(rhs) < 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator<=(const cstring<N>& lhs, std::string_view rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator<=(const cstring<N>& lhs, string_view rhs) noexcept {
|
||||
return lhs.compare(rhs) <= 0;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
[[nodiscard]] constexpr bool operator<=(std::string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
[[nodiscard]] constexpr bool operator<=(string_view lhs, const cstring<N>& rhs) noexcept {
|
||||
return lhs.compare(rhs) <= 0;
|
||||
}
|
||||
|
||||
|
@ -295,23 +324,9 @@ std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& o
|
|||
return os;
|
||||
}
|
||||
|
||||
// If need another optional type, define the macro NAMEOF_USING_ALIAS_STRING_VIEW.
|
||||
#if defined(NAMEOF_USING_ALIAS_STRING_VIEW)
|
||||
NAMEOF_USING_ALIAS_STRING_VIEW
|
||||
#else
|
||||
using string_view = std::string_view;
|
||||
#endif
|
||||
|
||||
// If need another optional type, define the macro NAMEOF_USING_ALIAS_STRING.
|
||||
#if defined(NAMEOF_USING_ALIAS_STRING)
|
||||
NAMEOF_USING_ALIAS_STRING
|
||||
#else
|
||||
using string = std::string;
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr std::string_view pretty_name(std::string_view name, bool remove_template_suffix = true) noexcept {
|
||||
constexpr string_view pretty_name(string_view name, bool remove_template_suffix = true) noexcept {
|
||||
if (name.size() >= 1 && (name[0] == '"' || name[0] == '\'')) {
|
||||
return {}; // Narrow multibyte string literal.
|
||||
} else if (name.size() >= 2 && name[0] == 'R' && (name[1] == '"' || name[1] == '\'')) {
|
||||
|
@ -411,7 +426,7 @@ constexpr I log2(I value) noexcept {
|
|||
static_assert(std::is_integral_v<I>, "nameof::detail::log2 requires integral type.");
|
||||
|
||||
auto ret = I{0};
|
||||
for (; value > I{1}; value >>= I{1}, ++ret) {};
|
||||
for (; value > I{1}; value >>= I{1}, ++ret) {}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -433,6 +448,10 @@ inline constexpr bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::de
|
|||
template <typename E, E V>
|
||||
constexpr auto n() noexcept {
|
||||
static_assert(is_enum_v<E>, "nameof::detail::n requires enum type.");
|
||||
constexpr auto custom_name = customize::enum_name<E>(V);
|
||||
|
||||
if constexpr (custom_name.empty()) {
|
||||
static_cast<void>(custom_name);
|
||||
#if defined(NAMEOF_ENUM_SUPPORTED) && NAMEOF_ENUM_SUPPORTED
|
||||
# if defined(__clang__) || defined(__GNUC__)
|
||||
constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2});
|
||||
|
@ -442,11 +461,14 @@ constexpr auto n() noexcept {
|
|||
if constexpr (name.size() > 0) {
|
||||
return cstring<name.size()>{name};
|
||||
} else {
|
||||
return std::string_view{};
|
||||
return string_view{};
|
||||
}
|
||||
#else
|
||||
return std::string_view{}; // Unsupported compiler.
|
||||
return string_view{}; // Unsupported compiler.
|
||||
#endif
|
||||
} else {
|
||||
return cstring<custom_name.size()>{custom_name};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E, E V>
|
||||
|
@ -466,7 +488,7 @@ constexpr int reflected_min() noexcept {
|
|||
if constexpr (IsFlags) {
|
||||
return 0;
|
||||
} else {
|
||||
constexpr auto lhs = enum_range<E>::min;
|
||||
constexpr auto lhs = customize::enum_range<E>::min;
|
||||
static_assert(lhs > (std::numeric_limits<std::int16_t>::min)(), "nameof::enum_range requires min must be greater than INT16_MIN.");
|
||||
constexpr auto rhs = (std::numeric_limits<U>::min)();
|
||||
|
||||
|
@ -485,7 +507,7 @@ constexpr int reflected_max() noexcept {
|
|||
if constexpr (IsFlags) {
|
||||
return std::numeric_limits<U>::digits - 1;
|
||||
} else {
|
||||
constexpr auto lhs = enum_range<E>::max;
|
||||
constexpr auto lhs = customize::enum_range<E>::max;
|
||||
static_assert(lhs < (std::numeric_limits<std::int16_t>::max)(), "nameof::enum_range requires max must be less than INT16_MAX.");
|
||||
constexpr auto rhs = (std::numeric_limits<U>::max)();
|
||||
|
||||
|
@ -514,11 +536,23 @@ constexpr E value(std::size_t i) noexcept {
|
|||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr std::size_t values_count(const std::array<bool, N>& valid) noexcept {
|
||||
auto count = std::size_t{0};
|
||||
for (std::size_t i = 0; i < valid.size(); ++i) {
|
||||
if (valid[i]) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename E, bool IsFlags, int Min, std::size_t... I>
|
||||
constexpr auto values(std::index_sequence<I...>) noexcept {
|
||||
static_assert(is_enum_v<E>, "nameof::detail::values requires enum type.");
|
||||
constexpr std::array<bool, sizeof...(I)> valid{{is_valid<E, value<E, Min, IsFlags>(I)>()...}};
|
||||
constexpr std::size_t count = ((valid[I] ? std::size_t{1} : std::size_t{0}) + ...);
|
||||
constexpr std::size_t count = values_count(valid);
|
||||
|
||||
std::array<E, count> values{};
|
||||
for (std::size_t i = 0, v = 0; v < count; ++i) {
|
||||
|
@ -641,7 +675,15 @@ struct nameof_type_supported
|
|||
: std::false_type {};
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
template <typename... T>
|
||||
struct nameof_type_rtti_supported
|
||||
#if defined(NAMEOF_TYPE_RTTI_SUPPORTED) && NAMEOF_TYPE_RTTI_SUPPORTED || defined(NAMEOF_TYPE_NO_CHECK_SUPPORT)
|
||||
: std::true_type {};
|
||||
#else
|
||||
: std::false_type {};
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
template <typename T>
|
||||
struct identity {
|
||||
using type = T;
|
||||
|
@ -654,37 +696,123 @@ using identity = T;
|
|||
template <typename T>
|
||||
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
|
||||
template <typename T, typename R>
|
||||
using enable_if_has_short_name_t = std::enable_if_t<!std::is_array_v<T> && !std::is_pointer_v<T>, R>;
|
||||
|
||||
template <typename... T>
|
||||
constexpr auto n() noexcept {
|
||||
# if defined(_MSC_VER) && !defined(__clang__)
|
||||
constexpr auto custom_name = customize::type_name<typename T::type...>();
|
||||
#else
|
||||
constexpr auto custom_name = customize::type_name<T...>();
|
||||
# endif
|
||||
|
||||
if constexpr (custom_name.empty()) {
|
||||
static_cast<void>(custom_name);
|
||||
#if defined(NAMEOF_TYPE_SUPPORTED) && NAMEOF_TYPE_SUPPORTED
|
||||
# if defined(__clang__)
|
||||
constexpr std::string_view name{__PRETTY_FUNCTION__ + 31, sizeof(__PRETTY_FUNCTION__) - 34};
|
||||
constexpr string_view name{__PRETTY_FUNCTION__ + 31, sizeof(__PRETTY_FUNCTION__) - 34};
|
||||
# elif defined(__GNUC__)
|
||||
constexpr std::string_view name{__PRETTY_FUNCTION__ + 46, sizeof(__PRETTY_FUNCTION__) - 49};
|
||||
constexpr string_view name{__PRETTY_FUNCTION__ + 46, sizeof(__PRETTY_FUNCTION__) - 49};
|
||||
# elif defined(_MSC_VER)
|
||||
constexpr std::string_view name{__FUNCSIG__ + 63, sizeof(__FUNCSIG__) - 81 - (__FUNCSIG__[sizeof(__FUNCSIG__) - 19] == ' ' ? 1 : 0)};
|
||||
constexpr string_view name{__FUNCSIG__ + 63, sizeof(__FUNCSIG__) - 81 - (__FUNCSIG__[sizeof(__FUNCSIG__) - 19] == ' ' ? 1 : 0)};
|
||||
# endif
|
||||
|
||||
return cstring<name.size()>{name};
|
||||
#else
|
||||
return std::string_view{}; // Unsupported compiler.
|
||||
return string_view{}; // Unsupported compiler.
|
||||
#endif
|
||||
} else {
|
||||
return cstring<custom_name.size()>{custom_name};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
inline constexpr auto type_name_v = n<T...>();
|
||||
|
||||
#if __has_include(<cxxabi.h>)
|
||||
inline std::string demangle(const char* tn) {
|
||||
auto dmg = abi::__cxa_demangle(tn, nullptr, nullptr, nullptr);
|
||||
auto r = std::string{dmg};
|
||||
template <typename T>
|
||||
string nameof_type_rtti(const char* tn) {
|
||||
static_assert(nameof_type_rtti_supported<T>::value, "nameof::nameof_type_rtti unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
const auto dmg = abi::__cxa_demangle(tn, nullptr, nullptr, nullptr);
|
||||
const auto name = string{dmg};
|
||||
std::free(dmg);
|
||||
assert(name.size() > 0 && "Type does not have a name.");
|
||||
|
||||
return r;
|
||||
return name;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
string nameof_full_type_rtti(const char* tn) {
|
||||
static_assert(nameof_type_rtti_supported<T>::value, "nameof::nameof_type_rtti unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
const auto dmg = abi::__cxa_demangle(tn, nullptr, nullptr, nullptr);
|
||||
auto name = string{dmg};
|
||||
std::free(dmg);
|
||||
assert(name.size() > 0 && "Type does not have a name.");
|
||||
if constexpr (std::is_const_v<std::remove_reference_t<T>>) {
|
||||
name = "const " + name;
|
||||
}
|
||||
if constexpr (std::is_volatile_v<std::remove_reference_t<T>>) {
|
||||
name = "volatile " + name;
|
||||
}
|
||||
if constexpr (std::is_lvalue_reference_v<T>) {
|
||||
name += '&';
|
||||
}
|
||||
if constexpr (std::is_rvalue_reference_v<T>) {
|
||||
name += "&&";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
template <typename T, enable_if_has_short_name_t<T, int> = 0>
|
||||
string nameof_short_type_rtti(const char* tn) {
|
||||
static_assert(nameof_type_rtti_supported<T>::value, "nameof::nameof_type_rtti unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
const auto dmg = abi::__cxa_demangle(tn, nullptr, nullptr, nullptr);
|
||||
const auto name = string{pretty_name(dmg)};
|
||||
std::free(dmg);
|
||||
assert(name.size() > 0 && "Type does not have a short name.");
|
||||
|
||||
return name;
|
||||
}
|
||||
#else
|
||||
constexpr std::string_view demangle(const char* tn) noexcept {
|
||||
return {tn};
|
||||
template <typename T>
|
||||
string nameof_type_rtti(const char* tn) noexcept {
|
||||
static_assert(nameof_type_rtti_supported<T>::value, "nameof::nameof_type_rtti unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
const auto name = string_view{tn};
|
||||
assert(name.size() > 0 && "Type does not have a name.");
|
||||
|
||||
return {name.begin(), name.end()};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
string nameof_full_type_rtti(const char* tn) noexcept {
|
||||
static_assert(nameof_type_rtti_supported<T>::value, "nameof::nameof_type_rtti unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
auto name = string{tn};
|
||||
assert(name.size() > 0 && "Type does not have a name.");
|
||||
if constexpr (std::is_const_v<std::remove_reference_t<T>>) {
|
||||
name = "const " + name;
|
||||
}
|
||||
if constexpr (std::is_volatile_v<std::remove_reference_t<T>>) {
|
||||
name = "volatile " + name;
|
||||
}
|
||||
if constexpr (std::is_lvalue_reference_v<T>) {
|
||||
name += '&';
|
||||
}
|
||||
if constexpr (std::is_rvalue_reference_v<T>) {
|
||||
name += "&&";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
template <typename T, enable_if_has_short_name_t<T, int> = 0>
|
||||
string nameof_short_type_rtti(const char* tn) noexcept {
|
||||
static_assert(nameof_type_rtti_supported<T>::value, "nameof::nameof_type_rtti unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
const auto name = pretty_name(tn);
|
||||
assert(name.size() > 0 && "Type does not have a short name.");
|
||||
|
||||
return {name.begin(), name.end()};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -693,19 +821,22 @@ constexpr std::string_view demangle(const char* tn) noexcept {
|
|||
// Checks is nameof_type supported compiler.
|
||||
inline constexpr bool is_nameof_type_supported = detail::nameof_type_supported<void>::value;
|
||||
|
||||
// Checks is nameof_type_rtti supported compiler.
|
||||
inline constexpr bool is_nameof_type_rtti_supported = detail::nameof_type_rtti_supported<void>::value;
|
||||
|
||||
// Checks is nameof_enum supported compiler.
|
||||
inline constexpr bool is_nameof_enum_supported = detail::nameof_enum_supported<void>::value;
|
||||
|
||||
// Obtains simple (unqualified) string name of enum variable.
|
||||
// Obtains simple (unqualified) name of enum variable.
|
||||
template <typename E>
|
||||
[[nodiscard]] constexpr auto nameof_enum(E value) noexcept -> detail::enable_if_enum_t<E, std::string_view> {
|
||||
[[nodiscard]] constexpr auto nameof_enum(E value) noexcept -> detail::enable_if_enum_t<E, string_view> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = std::underlying_type_t<D>;
|
||||
static_assert(detail::nameof_enum_supported<D>::value, "nameof::nameof_enum unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
static_assert(detail::count_v<D> > 0, "nameof::nameof_enum requires enum implementation and valid max and min.");
|
||||
|
||||
if (const auto i = static_cast<int>(value) - detail::min_v<D>; static_cast<U>(value) >= static_cast<U>(detail::min_v<D>) &&
|
||||
static_cast<U>(value) <= static_cast<U>(detail::max_v<D>)) {
|
||||
const bool valid = static_cast<U>(value) >= static_cast<U>(detail::min_v<D>) && static_cast<U>(value) <= static_cast<U>(detail::max_v<D>);
|
||||
if (const auto i = static_cast<int>(value) - detail::min_v<D>; valid) {
|
||||
if constexpr (detail::is_sparse_v<D>) {
|
||||
if (const auto idx = detail::indexes_v<D>[i]; idx != detail::invalid_index_v<D>) {
|
||||
return detail::strings_v<D>[idx];
|
||||
|
@ -715,19 +846,20 @@ template <typename E>
|
|||
}
|
||||
}
|
||||
|
||||
assert(valid && "enum variable does not have a name.");
|
||||
return {}; // Value out of range.
|
||||
}
|
||||
|
||||
// Obtains simple (unqualified) string name of enum-flags variable.
|
||||
// Obtains simple (unqualified) name of enum-flags variable.
|
||||
template <typename E>
|
||||
[[nodiscard]] auto nameof_enum_flag(E value) -> detail::enable_if_enum_t<E, std::string> {
|
||||
[[nodiscard]] auto nameof_enum_flag(E value) -> detail::enable_if_enum_t<E, string> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = std::underlying_type_t<D>;
|
||||
static_assert(detail::nameof_enum_supported<D>::value, "nameof::nameof_enum_flag unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
static_assert(detail::count_v<D, true> > 0, "nameof::nameof_enum_flag requires enum-flags implementation.");
|
||||
constexpr auto size = detail::is_sparse_v<D, true> ? detail::count_v<D, true> : detail::range_size_v<D, true>;
|
||||
|
||||
std::string name;
|
||||
string name;
|
||||
auto check_value = U{0};
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
if (const auto v = static_cast<U>(detail::get_value<D, true>(i)); (static_cast<U>(value) & v) != 0) {
|
||||
|
@ -743,117 +875,125 @@ template <typename E>
|
|||
}
|
||||
}
|
||||
|
||||
if (check_value != 0 && check_value == static_cast<U>(value)) {
|
||||
const bool valid = check_value != 0 && check_value == static_cast<U>(value);
|
||||
if (valid) {
|
||||
return name;
|
||||
}
|
||||
|
||||
assert(valid && "enum-flags variable does not have a name.");
|
||||
return {}; // Invalid value or out of range.
|
||||
}
|
||||
|
||||
// Obtains simple (unqualified) string name of static storage enum variable.
|
||||
// Obtains simple (unqualified) name of static storage enum variable.
|
||||
// This version is much lighter on the compile times and is not restricted to the enum_range limitation.
|
||||
template <auto V>
|
||||
[[nodiscard]] constexpr auto nameof_enum() noexcept -> detail::enable_if_enum_t<decltype(V), std::string_view> {
|
||||
[[nodiscard]] constexpr auto nameof_enum() noexcept -> detail::enable_if_enum_t<decltype(V), string_view> {
|
||||
using D = std::decay_t<decltype(V)>;
|
||||
static_assert(detail::nameof_enum_supported<D>::value, "nameof::nameof_enum unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
constexpr std::string_view name = detail::enum_name_v<D, V>;
|
||||
constexpr string_view name = detail::enum_name_v<D, V>;
|
||||
static_assert(name.size() > 0, "Enum value does not have a name.");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
// Obtains string name of type, reference and cv-qualifiers are ignored.
|
||||
// Obtains name of type, reference and cv-qualifiers are ignored.
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr std::string_view nameof_type() noexcept {
|
||||
[[nodiscard]] constexpr string_view nameof_type() noexcept {
|
||||
static_assert(detail::nameof_type_supported<T>::value, "nameof::nameof_type unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
using U = detail::identity<detail::remove_cvref_t<T>>;
|
||||
constexpr std::string_view name = detail::type_name_v<U>;
|
||||
constexpr string_view name = detail::type_name_v<U>;
|
||||
static_assert(name.size() > 0, "Type does not have a name.");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
// Obtains string name of full type, with reference and cv-qualifiers.
|
||||
// Obtains full name of type, with reference and cv-qualifiers.
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr std::string_view nameof_full_type() noexcept {
|
||||
[[nodiscard]] constexpr string_view nameof_full_type() noexcept {
|
||||
static_assert(detail::nameof_type_supported<T>::value, "nameof::nameof_type unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
using U = detail::identity<T>;
|
||||
constexpr std::string_view name = detail::type_name_v<U>;
|
||||
static_assert(name.size() > 0, "Type does not have a name.");
|
||||
constexpr string_view name = detail::type_name_v<U>;
|
||||
static_assert(name.size() > 0, "Type does not have a full name.");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
// Obtains string name of short type.
|
||||
// Obtains short name of type.
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr std::string_view nameof_short_type() noexcept {
|
||||
[[nodiscard]] constexpr auto nameof_short_type() noexcept -> detail::enable_if_has_short_name_t<T, string_view> {
|
||||
static_assert(detail::nameof_type_supported<T>::value, "nameof::nameof_type unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
using U = detail::identity<detail::remove_cvref_t<T>>;
|
||||
constexpr std::string_view name = detail::pretty_name(detail::type_name_v<U>);
|
||||
static_assert(name.size() > 0, "Type does not have a name.");
|
||||
constexpr string_view name = detail::pretty_name(detail::type_name_v<U>);
|
||||
static_assert(name.size() > 0, "Type does not have a short name.");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
} // namespace nameof
|
||||
|
||||
// Obtains simple (unqualified) string name of variable, function, macro.
|
||||
// Obtains name of variable, function, macro.
|
||||
#define NAMEOF(...) []() constexpr noexcept { \
|
||||
::std::void_t<decltype(__VA_ARGS__)>(); \
|
||||
constexpr auto __name = ::nameof::detail::pretty_name(#__VA_ARGS__, true); \
|
||||
static_assert(__name.size() > 0, "Expression does not have a name."); \
|
||||
constexpr auto __size = __name.size(); \
|
||||
constexpr auto __nameof = ::nameof::cstring<__size>{__name}; \
|
||||
return __nameof; }()
|
||||
constexpr auto _name = ::nameof::detail::pretty_name(#__VA_ARGS__); \
|
||||
static_assert(_name.size() > 0, "Expression does not have a name."); \
|
||||
constexpr auto _size = _name.size(); \
|
||||
constexpr auto _nameof = ::nameof::cstring<_size>{_name}; \
|
||||
return _nameof; }()
|
||||
|
||||
// Obtains simple (unqualified) full (with template suffix) string name of variable, function, macro.
|
||||
// Obtains full name of variable, function, macro.
|
||||
#define NAMEOF_FULL(...) []() constexpr noexcept { \
|
||||
::std::void_t<decltype(__VA_ARGS__)>(); \
|
||||
constexpr auto __name = ::nameof::detail::pretty_name(#__VA_ARGS__, false); \
|
||||
static_assert(__name.size() > 0, "Expression does not have a name."); \
|
||||
constexpr auto __size = __name.size(); \
|
||||
constexpr auto __nameof_full = ::nameof::cstring<__size>{__name}; \
|
||||
return __nameof_full; }()
|
||||
constexpr auto _name = ::nameof::detail::pretty_name(#__VA_ARGS__, false); \
|
||||
static_assert(_name.size() > 0, "Expression does not have a name."); \
|
||||
constexpr auto _size = _name.size(); \
|
||||
constexpr auto _nameof_full = ::nameof::cstring<_size>{_name}; \
|
||||
return _nameof_full; }()
|
||||
|
||||
// Obtains raw string name of variable, function, macro.
|
||||
// Obtains raw name of variable, function, macro.
|
||||
#define NAMEOF_RAW(...) []() constexpr noexcept { \
|
||||
::std::void_t<decltype(__VA_ARGS__)>(); \
|
||||
constexpr auto __name = ::std::string_view{#__VA_ARGS__}; \
|
||||
static_assert(__name.size() > 0, "Expression does not have a name."); \
|
||||
constexpr auto __size = __name.size(); \
|
||||
constexpr auto __nameof_raw = ::nameof::cstring<__size>{__name}; \
|
||||
return __nameof_raw; }()
|
||||
constexpr auto _name = ::nameof::string_view{#__VA_ARGS__}; \
|
||||
static_assert(_name.size() > 0, "Expression does not have a name."); \
|
||||
constexpr auto _size = _name.size(); \
|
||||
constexpr auto _nameof_raw = ::nameof::cstring<_size>{_name}; \
|
||||
return _nameof_raw; }()
|
||||
|
||||
// Obtains simple (unqualified) string name of enum variable.
|
||||
// Obtains name of enum variable.
|
||||
#define NAMEOF_ENUM(...) ::nameof::nameof_enum<::std::decay_t<decltype(__VA_ARGS__)>>(__VA_ARGS__)
|
||||
|
||||
// Obtains simple (unqualified) string name of static storage enum variable.
|
||||
// Obtains name of static storage enum variable.
|
||||
// This version is much lighter on the compile times and is not restricted to the enum_range limitation.
|
||||
#define NAMEOF_ENUM_CONST(...) ::nameof::nameof_enum<__VA_ARGS__>()
|
||||
|
||||
// Obtains simple (unqualified) string name of enum-flags variable.
|
||||
// Obtains name of enum-flags variable.
|
||||
#define NAMEOF_ENUM_FLAG(...) ::nameof::nameof_enum_flag<::std::decay_t<decltype(__VA_ARGS__)>>(__VA_ARGS__)
|
||||
|
||||
// Obtains string name of type, reference and cv-qualifiers are ignored.
|
||||
// Obtains type name, reference and cv-qualifiers are ignored.
|
||||
#define NAMEOF_TYPE(...) ::nameof::nameof_type<__VA_ARGS__>()
|
||||
|
||||
// Obtains string name type of expression, reference and cv-qualifiers are ignored.
|
||||
// Obtains type name of expression, reference and cv-qualifiers are ignored.
|
||||
#define NAMEOF_TYPE_EXPR(...) ::nameof::nameof_type<decltype(__VA_ARGS__)>()
|
||||
|
||||
// Obtains string name of full type, with reference and cv-qualifiers.
|
||||
// Obtains full type name, with reference and cv-qualifiers.
|
||||
#define NAMEOF_FULL_TYPE(...) ::nameof::nameof_full_type<__VA_ARGS__>()
|
||||
|
||||
// Obtains string name full type of expression, with reference and cv-qualifiers.
|
||||
// Obtains full type name of expression, with reference and cv-qualifiers.
|
||||
#define NAMEOF_FULL_TYPE_EXPR(...) ::nameof::nameof_full_type<decltype(__VA_ARGS__)>()
|
||||
|
||||
// Obtains string name of short type.
|
||||
// Obtains short type name.
|
||||
#define NAMEOF_SHORT_TYPE(...) ::nameof::nameof_short_type<__VA_ARGS__>()
|
||||
|
||||
// Obtains string name short type of expression.
|
||||
// Obtains short type name of expression.
|
||||
#define NAMEOF_SHORT_TYPE_EXPR(...) ::nameof::nameof_short_type<decltype(__VA_ARGS__)>()
|
||||
|
||||
// Obtains string name of type, using RTTI.
|
||||
#define NAMEOF_TYPE_RTTI(...) ::nameof::detail::demangle(typeid(__VA_ARGS__).name())
|
||||
// Obtains type name, with reference and cv-qualifiers, using RTTI.
|
||||
#define NAMEOF_TYPE_RTTI(...) ::nameof::detail::nameof_type_rtti<decltype(__VA_ARGS__)>(typeid(__VA_ARGS__).name())
|
||||
|
||||
// Obtains full type name, using RTTI.
|
||||
#define NAMEOF_FULL_TYPE_RTTI(...) ::nameof::detail::nameof_full_type_rtti<decltype(__VA_ARGS__)>(typeid(__VA_ARGS__).name())
|
||||
|
||||
// Obtains short type name, using RTTI.
|
||||
#define NAMEOF_SHORT_TYPE_RTTI(...) ::nameof::detail::nameof_short_type_rtti<decltype(__VA_ARGS__)>(typeid(__VA_ARGS__).name())
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
|
|
615
test/test.cpp
615
test/test.cpp
|
@ -30,6 +30,12 @@
|
|||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define NAMEOF_DEBUG_REQUIRE(...) REQUIRE(__VA_ARGS__)
|
||||
#else
|
||||
# define NAMEOF_DEBUG_REQUIRE(...)
|
||||
#endif
|
||||
|
||||
struct SomeStruct {
|
||||
int somefield = 0;
|
||||
|
||||
|
@ -93,15 +99,18 @@ enum class BigFlags : std::uint64_t {
|
|||
D = (static_cast<std::uint64_t>(0x1) << 63),
|
||||
};
|
||||
|
||||
namespace nameof {
|
||||
template <>
|
||||
struct enum_range<number> {
|
||||
struct nameof::customize::enum_range<number> {
|
||||
static_assert(std::is_enum_v<number>, "nameof::enum_range<number> requires enum type.");
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
static_assert(max > min, "nameof::enum_range<number> requires max > min.");
|
||||
};
|
||||
} // namespace nameof
|
||||
|
||||
struct TestRtti{
|
||||
struct Base { virtual ~Base() = default; };
|
||||
struct Derived : Base {};
|
||||
};
|
||||
|
||||
SomeStruct struct_var;
|
||||
Long othervar;
|
||||
|
@ -243,70 +252,6 @@ TEST_CASE("NAMEOF_RAW") {
|
|||
|
||||
static_assert(nameof::is_nameof_enum_supported, "nameof::nameof_enum: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
|
||||
TEST_CASE("NAMEOF_ENUM") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = NAMEOF_ENUM(cr);
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(NAMEOF_ENUM(Color::BLUE) == "BLUE");
|
||||
REQUIRE(NAMEOF_ENUM(cm[1]) == "GREEN");
|
||||
REQUIRE(NAMEOF_ENUM(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = NAMEOF_ENUM(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::two) == "two");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::three) == "three");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::many).empty());
|
||||
REQUIRE(NAMEOF_ENUM(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = NAMEOF_ENUM(dr);
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Up) == "Up");
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Left) == "Left");
|
||||
REQUIRE(NAMEOF_ENUM(static_cast<Directions>(0)).empty());
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = NAMEOF_ENUM(nt);
|
||||
REQUIRE(NAMEOF_ENUM(number::one) == "one");
|
||||
REQUIRE(NAMEOF_ENUM(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
REQUIRE(NAMEOF_ENUM(number::four).empty());
|
||||
REQUIRE(NAMEOF_ENUM(static_cast<number>(0)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_ENUM_CONST") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = NAMEOF_ENUM_CONST(cr);
|
||||
constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Color::BLUE) == "BLUE");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(cm[1]) == "GREEN");
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = NAMEOF_ENUM_CONST(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Numbers::two) == "two");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Numbers::three) == "three");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Numbers::many) == "many");
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = NAMEOF_ENUM_CONST(dr);
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Directions::Up) == "Up");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Directions::Left) == "Left");
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = NAMEOF_ENUM_CONST(nt);
|
||||
REQUIRE(NAMEOF_ENUM_CONST(number::one) == "one");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(number::four) == "four");
|
||||
}
|
||||
|
||||
TEST_CASE("nameof_enum") {
|
||||
SECTION("automatic storage") {
|
||||
constexpr Color cr = Color::RED;
|
||||
|
@ -315,15 +260,15 @@ TEST_CASE("nameof_enum") {
|
|||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(nameof::nameof_enum(Color::BLUE) == "BLUE");
|
||||
REQUIRE(nameof::nameof_enum(cm[1]) == "GREEN");
|
||||
REQUIRE(nameof::nameof_enum(static_cast<Color>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = nameof::nameof_enum(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(nameof::nameof_enum(Numbers::two) == "two");
|
||||
REQUIRE(nameof::nameof_enum(Numbers::three) == "three");
|
||||
REQUIRE(nameof::nameof_enum(Numbers::many).empty());
|
||||
REQUIRE(nameof::nameof_enum(static_cast<Numbers>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(Numbers::many).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = nameof::nameof_enum(dr);
|
||||
|
@ -331,15 +276,15 @@ TEST_CASE("nameof_enum") {
|
|||
REQUIRE(nameof::nameof_enum(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(nameof::nameof_enum(Directions::Left) == "Left");
|
||||
REQUIRE(nameof::nameof_enum(static_cast<Directions>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Directions>(0)).empty());
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = nameof::nameof_enum(nt);
|
||||
REQUIRE(nameof::nameof_enum(number::one) == "one");
|
||||
REQUIRE(nameof::nameof_enum(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
REQUIRE(nameof::nameof_enum(number::four).empty());
|
||||
REQUIRE(nameof::nameof_enum(static_cast<number>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(number::four).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<number>(0)).empty());
|
||||
}
|
||||
|
||||
SECTION("static storage") {
|
||||
|
@ -380,11 +325,11 @@ TEST_CASE("nameof_enum_flag") {
|
|||
REQUIRE(af_name == "HasClaws");
|
||||
REQUIRE(nameof::nameof_enum_flag(AnimalFlags::EatsFish) == "EatsFish");
|
||||
REQUIRE(nameof::nameof_enum_flag(afm[1]) == "CanFly");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(0)).empty());
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(1 | 2)) == "HasClaws|CanFly");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(1 | 2 | 4)) == "HasClaws|CanFly|EatsFish");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(1 | 0 | 8)) == "HasClaws|Endangered");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(0)).empty());
|
||||
|
||||
constexpr BigFlags bf = BigFlags::A;
|
||||
auto bf_name = nameof::nameof_enum_flag(bf);
|
||||
|
@ -392,15 +337,79 @@ TEST_CASE("nameof_enum_flag") {
|
|||
REQUIRE(bf_name == "A");
|
||||
REQUIRE(nameof::nameof_enum_flag(BigFlags::C) == "C");
|
||||
REQUIRE(nameof::nameof_enum_flag(bfm[1]) == "B");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(0)).empty());
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 2)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 2)).empty());
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20))) == "A|B");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20) | (static_cast<std::uint64_t>(0x1) << 63))) == "A|B|D");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 0 | (static_cast<std::uint64_t>(0x1) << 40))) == "A|C");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 0 | (static_cast<std::uint64_t>(0x1) << 40))) == "A|C");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 1)) == "A|D");
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(2)).empty());
|
||||
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 2)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(2)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 2)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_ENUM") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = NAMEOF_ENUM(cr);
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(NAMEOF_ENUM(Color::BLUE) == "BLUE");
|
||||
REQUIRE(NAMEOF_ENUM(cm[1]) == "GREEN");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = NAMEOF_ENUM(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::two) == "two");
|
||||
REQUIRE(NAMEOF_ENUM(Numbers::three) == "three");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(Numbers::many).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = NAMEOF_ENUM(dr);
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Up) == "Up");
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(NAMEOF_ENUM(Directions::Left) == "Left");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<Directions>(0)).empty());
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = NAMEOF_ENUM(nt);
|
||||
REQUIRE(NAMEOF_ENUM(number::one) == "one");
|
||||
REQUIRE(NAMEOF_ENUM(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(number::four).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<number>(0)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_ENUM_CONST") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = NAMEOF_ENUM_CONST(cr);
|
||||
constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Color::BLUE) == "BLUE");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(cm[1]) == "GREEN");
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = NAMEOF_ENUM_CONST(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Numbers::two) == "two");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Numbers::three) == "three");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Numbers::many) == "many");
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = NAMEOF_ENUM_CONST(dr);
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Directions::Up) == "Up");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(Directions::Left) == "Left");
|
||||
|
||||
constexpr number nt = number::three;
|
||||
constexpr auto nt_name = NAMEOF_ENUM_CONST(nt);
|
||||
REQUIRE(NAMEOF_ENUM_CONST(number::one) == "one");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(number::two) == "two");
|
||||
REQUIRE(nt_name == "three");
|
||||
REQUIRE(NAMEOF_ENUM_CONST(number::four) == "four");
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_ENUM_FLAG") {
|
||||
|
@ -411,11 +420,11 @@ TEST_CASE("NAMEOF_ENUM_FLAG") {
|
|||
REQUIRE(NAMEOF_ENUM_FLAG(afm[1]) == "CanFly");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(AnimalFlags::EatsFish) == "EatsFish");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(AnimalFlags::Endangered) == "Endangered");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(0)).empty());
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 2)) == "HasClaws|CanFly");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 2 | 4)) == "HasClaws|CanFly|EatsFish");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 0 | 8)) == "HasClaws|Endangered");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(0)).empty());
|
||||
|
||||
constexpr BigFlags bf = BigFlags::A;
|
||||
auto bf_name = NAMEOF_ENUM_FLAG(bf);
|
||||
|
@ -424,13 +433,13 @@ TEST_CASE("NAMEOF_ENUM_FLAG") {
|
|||
REQUIRE(NAMEOF_ENUM_FLAG(bfm[1]) == "B");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::C) == "C");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::D) == "D");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(0)).empty());
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | 2)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(0)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | 2)).empty());
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20))) == "A|B");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20) | (static_cast<std::uint64_t>(0x1) << 63))) == "A|B|D");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 1)) == "A|D");
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(2)).empty());
|
||||
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 2)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(2)).empty());
|
||||
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 2)).empty());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -439,106 +448,59 @@ TEST_CASE("NAMEOF_ENUM_FLAG") {
|
|||
|
||||
static_assert(nameof::is_nameof_type_supported, "nameof::nameof_type: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_FULL_TYPE_EXPR(struct_var);
|
||||
TEST_CASE("nameof::nameof_type") {
|
||||
constexpr auto type_name = nameof::nameof_type<decltype(struct_var)>();
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct &");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int> &&");
|
||||
REQUIRE(nameof::nameof_type<Color>() == "Color");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "struct SomeStruct &");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "struct SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "struct SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "struct SomeStruct const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "class SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "struct Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "struct Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "struct Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "enum Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int> const &&");
|
||||
REQUIRE(nameof::nameof_type<Color>() == "enum Color");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct&");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct*");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct*");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int>&&");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE") {
|
||||
constexpr auto type_name = NAMEOF_FULL_TYPE(decltype(struct_var));
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "struct SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "struct SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "struct SomeStruct const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "class SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "struct Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "enum Color");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
|
||||
REQUIRE(nameof::nameof_type<Color>() == "Color");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -598,51 +560,22 @@ TEST_CASE("nameof::nameof_full_type") {
|
|||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_TYPE_EXPR(struct_var);
|
||||
#if defined(__clang__)
|
||||
TEST_CASE("nameof::nameof_short_type") {
|
||||
constexpr auto type_name = nameof::nameof_short_type<decltype(struct_var)>();
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_short_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_short_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_short_type<SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_short_type<const SomeStruct volatile>() == "SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
|
||||
REQUIRE(nameof::nameof_short_type<SomeClass<int>>() == "SomeClass");
|
||||
REQUIRE(nameof::nameof_short_type<const SomeClass<int> volatile>() == "SomeClass");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
REQUIRE(nameof::nameof_short_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_short_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_short_type<Long::LL>() == "LL");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "struct SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "struct Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "enum Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int>");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
|
||||
#endif
|
||||
REQUIRE(nameof::nameof_short_type<Color>() == "Color");
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_TYPE") {
|
||||
|
@ -701,72 +634,248 @@ TEST_CASE("NAMEOF_TYPE") {
|
|||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("nameof::nameof_type") {
|
||||
constexpr auto type_name = nameof::nameof_type<decltype(struct_var)>();
|
||||
TEST_CASE("NAMEOF_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_TYPE_EXPR(struct_var);
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int> *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(nameof::nameof_type<Color>() == "Color");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "struct SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "struct SomeStruct *");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "struct SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "struct SomeStruct const volatile *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "struct SomeStruct");
|
||||
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "class SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "class SomeClass<int> const volatile *");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "struct Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "struct Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "struct Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(nameof::nameof_type<Color>() == "enum Color");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "enum Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int>");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct*");
|
||||
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct*");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
|
||||
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct*");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
|
||||
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
|
||||
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int>*");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long>() == "Long");
|
||||
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(nameof::nameof_type<Color>() == "Color");
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE") {
|
||||
constexpr auto type_name = NAMEOF_FULL_TYPE(decltype(struct_var));
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "struct SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "struct SomeStruct &");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "struct SomeStruct const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "class SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "struct Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "enum Color");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_FULL_TYPE_EXPR(struct_var);
|
||||
#if defined(__clang__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct &");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int> &&");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(type_name == "struct SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "struct SomeStruct &");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "struct Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "struct Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "enum Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int> const &&");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct*");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct&");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int>&&");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_SHORT_TYPE") {
|
||||
constexpr auto type_name = NAMEOF_SHORT_TYPE(decltype(struct_var));
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(decltype(ref_s)) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(SomeStruct) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(SomeStruct &) == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(const SomeStruct volatile) == "SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(SomeClass<int>) == "SomeClass");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(const SomeClass<int> volatile) == "SomeClass");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(decltype(othervar)) == "Long");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(Long) == "Long");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(Long::LL) == "LL");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE(Color) == "Color");
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_SHORT_TYPE_EXPR") {
|
||||
constexpr auto type_name = NAMEOF_SHORT_TYPE_EXPR(struct_var);
|
||||
REQUIRE(type_name == "SomeStruct");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(ref_s) == "SomeStruct");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(othervar) == "Long");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(othervar.ll) == "LL");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(othervar.ll.field) == "int");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(Color::RED) == "Color");
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NAMEOF_TYPE_RTTI_SUPPORTED) && NAMEOF_TYPE_RTTI_SUPPORTED
|
||||
|
||||
TEST_CASE("NAMEOF_TYPE_RTTI") {
|
||||
#if defined(__clang__)
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(Color) == "Color");
|
||||
TestRtti::Base* ptr = new TestRtti::Derived();
|
||||
const TestRtti::Base& const_ref = *ptr;
|
||||
volatile TestRtti::Base& volatile_ref = *ptr;
|
||||
volatile const TestRtti::Base& cv_ref = *ptr;
|
||||
#if defined(__clang__) && !defined(_MSC_VER)
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(*ptr) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(const_ref) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(volatile_ref) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(cv_ref) == "TestRtti::Derived");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(Color) == "enum Color");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(*ptr) == "struct TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(const_ref) == "struct TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(volatile_ref) == "struct TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(cv_ref) == "struct TestRtti::Derived");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(Color) == "Color");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(*ptr) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(const_ref) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(volatile_ref) == "TestRtti::Derived");
|
||||
REQUIRE(NAMEOF_TYPE_RTTI(cv_ref) == "TestRtti::Derived");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_FULL_TYPE_RTTI") {
|
||||
TestRtti::Base* ptr = new TestRtti::Derived();
|
||||
const TestRtti::Base& const_ref = *ptr;
|
||||
volatile TestRtti::Base& volatile_ref = *ptr;
|
||||
volatile const TestRtti::Base& cv_ref = *ptr;
|
||||
#if defined(__clang__) && !defined(_MSC_VER)
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(*ptr) == "TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(const_ref) == "const TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(volatile_ref) == "volatile TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(cv_ref) == "volatile const TestRtti::Derived&");
|
||||
#elif defined(_MSC_VER)
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(*ptr) == "struct TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(const_ref) == "const struct TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(volatile_ref) == "volatile struct TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(cv_ref) == "volatile const struct TestRtti::Derived&");
|
||||
#elif defined(__GNUC__)
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(*ptr) == "TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(const_ref) == "const TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(volatile_ref) == "volatile TestRtti::Derived&");
|
||||
REQUIRE(NAMEOF_FULL_TYPE_RTTI(cv_ref) == "volatile const TestRtti::Derived&");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("NAMEOF_SHORT_TYPE_RTTI") {
|
||||
TestRtti::Base* ptr = new TestRtti::Derived();
|
||||
const TestRtti::Base& const_ref = *ptr;
|
||||
volatile TestRtti::Base& volatile_ref = *ptr;
|
||||
volatile const TestRtti::Base& cv_ref = *ptr;
|
||||
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(*ptr) == "Derived");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(const_ref) == "Derived");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(volatile_ref) == "Derived");
|
||||
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(cv_ref) == "Derived");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue