Wip v0.10.0 (#28)

This commit is contained in:
Daniil Goncharov 2020-12-29 20:45:54 +02:00 committed by GitHub
parent 308bbf9c68
commit 6fa49cca4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 916 additions and 621 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.8) 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) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(IS_TOPLEVEL_PROJECT TRUE) 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_EXAMPLES "Build nameof examples" ${IS_TOPLEVEL_PROJECT})
option(NAMEOF_OPT_BUILD_TESTS "Build and perform nameof tests" ${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) if(NAMEOF_OPT_BUILD_EXAMPLES)
add_subdirectory(example) add_subdirectory(example)
@ -33,18 +34,21 @@ write_basic_package_version_file(${PROJECT_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion) COMPATIBILITY AnyNewerVersion)
install(TARGETS ${PROJECT_NAME} if(NAMEOF_OPT_INSTALL)
EXPORT ${PROJECT_NAME}Config) 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}) DESTINATION lib/cmake/${PROJECT_NAME})
install(EXPORT ${PROJECT_NAME}Config install(EXPORT ${PROJECT_NAME}Config
NAMESPACE ${PROJECT_NAME}:: NAMESPACE ${PROJECT_NAME}::
DESTINATION lib/cmake/${PROJECT_NAME}) DESTINATION lib/cmake/${PROJECT_NAME})
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include
DESTINATION .) DESTINATION .)
export(EXPORT ${PROJECT_NAME}Config
NAMESPACE ${PROJECT_NAME}::)
endif()
export(EXPORT ${PROJECT_NAME}Config
NAMESPACE ${PROJECT_NAME}::)

View file

@ -8,7 +8,7 @@
``` ```
[![Github releases](https://img.shields.io/github/release/Neargye/nameof.svg)](https://github.com/Neargye/nameof/releases) [![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) [![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) [![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) [![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 * Nameof type
```cpp ```cpp
using T = const int&; const my::detail::SomeClass<int>& var_ref = var;
T var = 42;
// Name of variable type. // Name of variable type.
NAMEOF_TYPE_EXPR(var) -> "int" NAMEOF_TYPE_EXPR(var_ref) -> "my::detail::SomeClass<int>"
NAMEOF_FULL_TYPE_EXPR(var) -> "const int&" nameof::nameof_type<decltype(var_ref)>() -> "my::detail::SomeClass<int>"
nameof::nameof_type<decltype(var)>() -> "int" NAMEOF_FULL_TYPE_EXPR(var_ref) -> "const my::detail::SomeClass<int>&"
nameof::nameof_full_type<decltype(var)>() -> "const 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. // Name of type.
NAMEOF_TYPE(T) -> "int" NAMEOF_TYPE(T) ->"my::detail::SomeClass<int>"
NAMEOF_FULL_TYPE(T) -> "const int&" nameof::nameof_type<T>() -> "my::detail::SomeClass<int>"
nameof::nameof_type<T>() -> "int" NAMEOF_FULL_TYPE(T) -> "const my::detail::SomeClass<int>&"
nameof::nameof_full_type<T>() -> "const 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 * Compile-time

View file

@ -6,23 +6,24 @@
## Nameof Type ## 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. * 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 ## 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. * 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]`. * Enum value must be in range `[NAMEOF_ENUM_RANGE_MIN, NAMEOF_ENUM_RANGE_MAX]`.
@ -40,74 +41,22 @@
#include <nameof.hpp> #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 ```cpp
#include <nameof.hpp> #include <nameof.hpp>
enum class number { one = 100, two = 200, three = 300 }; enum class number { one = 100, two = 200, three = 300 };
namespace nameof {
template <> template <>
struct enum_range<number> { struct nameof::customize::enum_range<number> {
static constexpr int min = 100; static constexpr int min = 100;
static constexpr int max = 300; 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 * Won't work if the enum is a forward declaration.
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>
* Intellisense Visual Studio may have some problems analyzing `nameof`. * Intellisense Visual Studio may have some problems analyzing `nameof`.

View file

@ -1,38 +1,39 @@
# Reference # Reference
* [`NAMEOF` macro that obtains simple (unqualified) string name of variable, function, macro.](#nameof) * [`NAMEOF` obtains simple 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_FULL` obtains full name of variable, function, macro.](#nameof_full)
* [`NAMEOF_RAW` macro that obtains raw string name of variable, function, macro.](#nameof_raw) * [`NAMEOF_RAW` obtains raw name of variable, function, macro.](#nameof_raw)
* [`nameof_enum` function that obtains simple (unqualified) string name of enum variable.](#nameof_enum) * [`NAMEOF_ENUM` obtains name of enum variable.](#nameof_enum)
* [`NAMEOF_ENUM` macro that obtains simple (unqualified) string name of enum variable.](#nameof_enum-1) * [`NAMEOF_ENUM_CONST` obtains name of static storage enum variable.](#nameof_enum_const)
* [`NAMEOF_ENUM_CONST` macro that obtains simple (unqualified) string name of static storage enum variable.](#nameof_enum_const) * [`NAMEOF_ENUM_FLAG` obtains name of enum-flags variable.](#nameof_enum_flag)
* [`nameof_enum_flag` function that obtains simple (unqualified) string name of enum variable.](#nameof_enum_flag) * [`NAMEOF_TYPE` obtains type name.](#nameof_type)
* [`NAMEOF_ENUM_FLAG` function that obtains simple (unqualified) string name of enum variable.](#nameof_enum_flag-1) * [`NAMEOF_FULL_TYPE` obtains full type name.](#nameof_full_type)
* [`nameof_type` function that obtains string name of type, reference and cv-qualifiers are ignored.](#nameof_type) * [`NAMEOF_SHORT_TYPE` obtains short type name.](#nameof_short_type)
* [`nameof_full_type` function that obtains string name of full type, with reference and cv-qualifiers.](#nameof_full_type) * [`NAMEOF_TYPE_EXPR` obtains type name of expression.](#nameof_type_expr)
* [`NAMEOF_TYPE` macro that obtains string name of type, reference and cv-qualifiers are ignored.](#nameof_type-1) * [`NAMEOF_FULL_TYPE_EXPR` obtains full type name of expression.](#nameof_full_type_expr)
* [`NAMEOF_FULL_TYPE` macro that obtains string name of full type, with reference and cv-qualifiers.](#nameof_full_type-1) * [`NAMEOF_SHORT_TYPE_EXPR` obtains short type name of expression.](#nameof_short_type_expr)
* [`NAMEOF_TYPE_EXPR` macro that obtains string name type of expression, reference and cv-qualifiers are ignored.](#nameof_type_expr) * [`NAMEOF_TYPE_RTTI` obtains type name, using RTTI.](#nameof_type_rtti)
* [`NAMEOF_FULL_TYPE_EXPR` macro that obtains string name full type of expression, with reference and cv-qualifiers.](#nameof_full_type_expr) * [`NAMEOF_FULL_TYPE_RTTI` obtains short type name, using RTTI.](#nameof_full_type_rtti)
* [`NAMEOF_TYPE_RTTI` macro that obtains string name type, using RTTI.](#nameof_type_rtti) * [`NAMEOF_SHORT_TYPE_RTTI` obtains short type name, using RTTI.](#nameof_short_type_rtti)
## Synopsis ## Synopsis
* Before use, read the [limitations](limitations.md) of functionality. * 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> * 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`. 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> * 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`. If nameof_enum used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_ENUM_NO_CHECK_SUPPORT`.
## `NAMEOF` ## `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."`. * If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
@ -59,9 +60,9 @@
## `NAMEOF_FULL` ## `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."`. * If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
@ -77,9 +78,9 @@
## `NAMEOF_RAW` ## `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."`. * 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_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` ## `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 * Examples
```cpp ```cpp
auto color = Color::RED; auto color = Color::RED;
NAMEOF_ENUM(color) -> "RED" NAMEOF_ENUM(color) -> "RED"
nameof::nameof_enum(color) -> "RED"
``` ```
## `NAMEOF_ENUM_CONST` ## `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). * 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 ```cpp
NAMEOF_ENUM_CONST(Color::GREEN) -> "GREEN" NAMEOF_ENUM_CONST(Color::GREEN) -> "GREEN"
``` nameof::nameof_enum<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_ENUM_FLAG` ## `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 * Examples
```cpp ```cpp
enum class AnimalFlags { HasClaws = 1 << 0, CanFly = 1 << 1, EatsFish = 1 << 2, Endangered = 1 << 3 }; enum class AnimalFlags { HasClaws = 1 << 0, CanFly = 1 << 1, EatsFish = 1 << 2, Endangered = 1 << 3 };
auto flag = AnimalFlags::Endangered; auto flag = AnimalFlags::Endangered;
NAMEOF_ENUM_FLAG(flag) -> "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) -> "CanFly|Endangered"
NAMEOF_ENUM_FLAG(flag) -> "HasClaws|CanFly" nameof_enum_flag(flag) -> "CanFly|Endangered"
NAMEOF_ENUM(HasClaws | CanFly) -> "" NAMEOF_ENUM(HasClaws | CanFly) -> ""
``` 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_TYPE` ## `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)`). * 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. * 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 * Examples
```cpp ```cpp
using T = const int&; using T = const int&;
NAMEOF_TYPE(T) -> "int" NAMEOF_TYPE(T) -> "int"
nameof::nameof_type<T>() -> "int"
``` ```
## `NAMEOF_FULL_TYPE` ## `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. * 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 * Examples
```cpp ```cpp
using T = const int&; using T = const int&;
NAMEOF_TYPE(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` ## `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. * 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 * Examples
@ -282,17 +225,18 @@
using T = const int&; using T = const int&;
T var = 42; T var = 42;
NAMEOF_TYPE_EXPR(var) -> "int" NAMEOF_TYPE_EXPR(var) -> "int"
nameof::nameof_type<decltype(var)>() -> "int"
``` ```
## `NAMEOF_FULL_TYPE_EXPR` ## `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. * 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 * Examples
@ -300,21 +244,62 @@
using T = const int&; using T = const int&;
T var = 42; T var = 42;
NAMEOF_FULL_TYPE_EXPR(var) -> "const int&" 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 * Examples
```cpp ```cpp
struct Base { virtual void foo() {} }; const my::detail::SomeClass<int> var;
struct Derived : Base {}; NAMEOF_SHORT_TYPE_EXPR(var) -> "SomeClass"
nameof::nameof_short_type<decltype(var)>() -> "SomeClass"
Base* ptr = new Derived(); ```
NAMEOF_TYPE_RTTI(ptr) -> "Base *"
NAMEOF_TYPE_RTTI(*ptr) -> "Derived" ## `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"
``` ```

View file

@ -9,8 +9,13 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
endif() endif()
endif() endif()
add_executable(example example.cpp) function(make_example target)
set_target_properties(example PROPERTIES CXX_EXTENSIONS OFF) add_executable(${target} ${target}.cpp)
target_compile_features(example PRIVATE cxx_std_17) set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF)
target_compile_options(example PRIVATE ${OPTIONS}) target_compile_features(${target} PRIVATE cxx_std_17)
target_link_libraries(example PRIVATE ${CMAKE_PROJECT_NAME}) target_compile_options(${target} PRIVATE ${OPTIONS})
target_link_libraries(${target} PRIVATE ${CMAKE_PROJECT_NAME})
endfunction()
make_example(example)
make_example(example_custom_name)

View file

@ -178,8 +178,8 @@ int main() {
#if defined(NAMEOF_TYPE_RTTI_SUPPORTED) #if defined(NAMEOF_TYPE_RTTI_SUPPORTED)
// Nameof type using RTTI. // Nameof type using RTTI.
Base* ptr = new Derived(); Base* ptr = new Derived();
std::cout << NAMEOF_TYPE_RTTI(ptr) << std::endl; // "Base *" 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; // 'Derived'
#endif #endif
// Some more complex example. // Some more complex example.

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

View file

@ -5,7 +5,7 @@
// | |\ | (_| | | | | | | __/ (_) | | | |____|_| |_| // | |\ | (_| | | | | | | __/ (_) | | | |____|_| |_|
// |_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____| // |_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____|
// https://github.com/Neargye/nameof // https://github.com/Neargye/nameof
// version 0.9.4 // version 0.9.5
// //
// Licensed under the MIT License <http://opensource.org/licenses/MIT>. // Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
@ -34,7 +34,7 @@
#define NAMEOF_VERSION_MAJOR 0 #define NAMEOF_VERSION_MAJOR 0
#define NAMEOF_VERSION_MINOR 9 #define NAMEOF_VERSION_MINOR 9
#define NAMEOF_VERSION_PATCH 4 #define NAMEOF_VERSION_PATCH 5
#include <array> #include <array>
#include <cassert> #include <cassert>
@ -118,15 +118,31 @@
namespace nameof { 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. // 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 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. // If need another range for specific enum type, add specialization enum_range for necessary enum type.
template <typename E> template <typename E>
struct enum_range { 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 min = NAMEOF_ENUM_RANGE_MIN;
inline static constexpr int max = NAMEOF_ENUM_RANGE_MAX; 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."); 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."); 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> template <std::size_t N>
class [[nodiscard]] cstring { 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: public:
using value_type = const char; using value_type = const char;
using size_type = std::size_t; using size_type = std::size_t;
@ -161,8 +186,8 @@ class [[nodiscard]] cstring {
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_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>{}} { constexpr explicit cstring(string_view str) noexcept : cstring{str, std::make_index_sequence<N>{}} {
assert(str.size() == N); assert(str.size() > 0 && str.size() == N);
} }
constexpr cstring() = delete; constexpr cstring() = delete;
@ -209,80 +234,84 @@ class [[nodiscard]] cstring {
[[nodiscard]] constexpr bool empty() const noexcept { return false; } [[nodiscard]] constexpr bool empty() const noexcept { return false; }
[[nodiscard]] constexpr int compare(std::string_view str) const noexcept { [[nodiscard]] constexpr int compare(string_view str) const noexcept {
return std::string_view{data(), size()}.compare(str); return string_view{data(), size()}.compare(str);
} }
[[nodiscard]] constexpr const char* c_str() const noexcept { return data(); } [[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]] string str() const { return {begin(), end()}; }
[[nodiscard]] std::basic_string<Char, Traits, Allocator> 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 string() const { return {begin(), end()}; }
[[nodiscard]] explicit operator std::basic_string<Char, Traits, Allocator>() 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> 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; return lhs.compare(rhs) == 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) == 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) != 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) != 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) > 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) > 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) >= 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) >= 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) < 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) < 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) <= 0;
} }
template <std::size_t N> 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; return lhs.compare(rhs) <= 0;
} }
@ -295,23 +324,9 @@ std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& o
return os; 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 { 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] == '\'')) { if (name.size() >= 1 && (name[0] == '"' || name[0] == '\'')) {
return {}; // Narrow multibyte string literal. return {}; // Narrow multibyte string literal.
} else if (name.size() >= 2 && name[0] == 'R' && (name[1] == '"' || name[1] == '\'')) { } 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."); static_assert(std::is_integral_v<I>, "nameof::detail::log2 requires integral type.");
auto ret = I{0}; auto ret = I{0};
for (; value > I{1}; value >>= I{1}, ++ret) {}; for (; value > I{1}; value >>= I{1}, ++ret) {}
return ret; return ret;
} }
@ -433,20 +448,27 @@ inline constexpr bool is_enum_v = std::is_enum_v<T> && std::is_same_v<T, std::de
template <typename E, E V> template <typename E, E V>
constexpr auto n() noexcept { constexpr auto n() noexcept {
static_assert(is_enum_v<E>, "nameof::detail::n requires enum type."); 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(NAMEOF_ENUM_SUPPORTED) && NAMEOF_ENUM_SUPPORTED
# if defined(__clang__) || defined(__GNUC__) # if defined(__clang__) || defined(__GNUC__)
constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2});
# elif defined(_MSC_VER) # elif defined(_MSC_VER)
constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17});
# endif # endif
if constexpr (name.size() > 0) { if constexpr (name.size() > 0) {
return cstring<name.size()>{name}; return cstring<name.size()>{name};
} else { } else {
return std::string_view{}; return string_view{};
} }
#else #else
return std::string_view{}; // Unsupported compiler. return string_view{}; // Unsupported compiler.
#endif #endif
} else {
return cstring<custom_name.size()>{custom_name};
}
} }
template <typename E, E V> template <typename E, E V>
@ -466,7 +488,7 @@ constexpr int reflected_min() noexcept {
if constexpr (IsFlags) { if constexpr (IsFlags) {
return 0; return 0;
} else { } 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."); 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)(); constexpr auto rhs = (std::numeric_limits<U>::min)();
@ -485,7 +507,7 @@ constexpr int reflected_max() noexcept {
if constexpr (IsFlags) { if constexpr (IsFlags) {
return std::numeric_limits<U>::digits - 1; return std::numeric_limits<U>::digits - 1;
} else { } 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."); 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)(); 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> template <typename E, bool IsFlags, int Min, std::size_t... I>
constexpr auto values(std::index_sequence<I...>) noexcept { constexpr auto values(std::index_sequence<I...>) noexcept {
static_assert(is_enum_v<E>, "nameof::detail::values requires enum type."); 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::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{}; std::array<E, count> values{};
for (std::size_t i = 0, v = 0; v < count; ++i) { for (std::size_t i = 0, v = 0; v < count; ++i) {
@ -641,7 +675,15 @@ struct nameof_type_supported
: std::false_type {}; : std::false_type {};
#endif #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> template <typename T>
struct identity { struct identity {
using type = T; using type = T;
@ -654,37 +696,123 @@ using identity = T;
template <typename T> template <typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<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> template <typename... T>
constexpr auto n() noexcept { constexpr auto n() noexcept {
#if defined(NAMEOF_TYPE_SUPPORTED) && NAMEOF_TYPE_SUPPORTED # if defined(_MSC_VER) && !defined(__clang__)
# if defined(__clang__) constexpr auto custom_name = customize::type_name<typename T::type...>();
constexpr std::string_view name{__PRETTY_FUNCTION__ + 31, sizeof(__PRETTY_FUNCTION__) - 34}; #else
# elif defined(__GNUC__) constexpr auto custom_name = customize::type_name<T...>();
constexpr std::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)};
# endif # endif
return cstring<name.size()>{name}; if constexpr (custom_name.empty()) {
static_cast<void>(custom_name);
#if defined(NAMEOF_TYPE_SUPPORTED) && NAMEOF_TYPE_SUPPORTED
# if defined(__clang__)
constexpr string_view name{__PRETTY_FUNCTION__ + 31, sizeof(__PRETTY_FUNCTION__) - 34};
# elif defined(__GNUC__)
constexpr string_view name{__PRETTY_FUNCTION__ + 46, sizeof(__PRETTY_FUNCTION__) - 49};
# elif defined(_MSC_VER)
constexpr string_view name{__FUNCSIG__ + 63, sizeof(__FUNCSIG__) - 81 - (__FUNCSIG__[sizeof(__FUNCSIG__) - 19] == ' ' ? 1 : 0)};
# endif
return cstring<name.size()>{name};
#else #else
return std::string_view{}; // Unsupported compiler. return string_view{}; // Unsupported compiler.
#endif #endif
} else {
return cstring<custom_name.size()>{custom_name};
}
} }
template <typename... T> template <typename... T>
inline constexpr auto type_name_v = n<T...>(); inline constexpr auto type_name_v = n<T...>();
#if __has_include(<cxxabi.h>) #if __has_include(<cxxabi.h>)
inline std::string demangle(const char* tn) { template <typename T>
auto dmg = abi::__cxa_demangle(tn, nullptr, nullptr, nullptr); string nameof_type_rtti(const char* tn) {
auto r = std::string{dmg}; 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); 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 #else
constexpr std::string_view demangle(const char* tn) noexcept { template <typename T>
return {tn}; 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 #endif
@ -693,19 +821,22 @@ constexpr std::string_view demangle(const char* tn) noexcept {
// Checks is nameof_type supported compiler. // Checks is nameof_type supported compiler.
inline constexpr bool is_nameof_type_supported = detail::nameof_type_supported<void>::value; 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. // Checks is nameof_enum supported compiler.
inline constexpr bool is_nameof_enum_supported = detail::nameof_enum_supported<void>::value; 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> 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 D = std::decay_t<E>;
using U = std::underlying_type_t<D>; 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::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."); 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>) && 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>);
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 constexpr (detail::is_sparse_v<D>) {
if (const auto idx = detail::indexes_v<D>[i]; idx != detail::invalid_index_v<D>) { if (const auto idx = detail::indexes_v<D>[i]; idx != detail::invalid_index_v<D>) {
return detail::strings_v<D>[idx]; 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. 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> 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 D = std::decay_t<E>;
using U = std::underlying_type_t<D>; 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::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."); 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>; 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}; auto check_value = U{0};
for (std::size_t i = 0; i < size; ++i) { 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) { 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; return name;
} }
assert(valid && "enum-flags variable does not have a name.");
return {}; // Invalid value or out of range. 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. // This version is much lighter on the compile times and is not restricted to the enum_range limitation.
template <auto V> 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)>; 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)."); 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."); static_assert(name.size() > 0, "Enum value does not have a name.");
return 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> 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)."); 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>>; 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."); static_assert(name.size() > 0, "Type does not have a name.");
return 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> 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)."); 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>; using U = detail::identity<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."); static_assert(name.size() > 0, "Type does not have a full name.");
return name; return name;
} }
// Obtains string name of short type. // Obtains short name of type.
template <typename T> 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)."); 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>>; using U = detail::identity<detail::remove_cvref_t<T>>;
constexpr std::string_view name = detail::pretty_name(detail::type_name_v<U>); constexpr string_view name = detail::pretty_name(detail::type_name_v<U>);
static_assert(name.size() > 0, "Type does not have a name."); static_assert(name.size() > 0, "Type does not have a short name.");
return name; return name;
} }
} // namespace nameof } // namespace nameof
// Obtains simple (unqualified) string name of variable, function, macro. // Obtains name of variable, function, macro.
#define NAMEOF(...) []() constexpr noexcept { \ #define NAMEOF(...) []() constexpr noexcept { \
::std::void_t<decltype(__VA_ARGS__)>(); \
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 full name of variable, function, macro.
#define NAMEOF_FULL(...) []() constexpr noexcept { \
::std::void_t<decltype(__VA_ARGS__)>(); \ ::std::void_t<decltype(__VA_ARGS__)>(); \
constexpr auto __name = ::nameof::detail::pretty_name(#__VA_ARGS__, true); \ constexpr auto _name = ::nameof::detail::pretty_name(#__VA_ARGS__, false); \
static_assert(__name.size() > 0, "Expression does not have a name."); \ static_assert(_name.size() > 0, "Expression does not have a name."); \
constexpr auto __size = __name.size(); \ constexpr auto _size = _name.size(); \
constexpr auto __nameof = ::nameof::cstring<__size>{__name}; \ constexpr auto _nameof_full = ::nameof::cstring<_size>{_name}; \
return __nameof; }() return _nameof_full; }()
// Obtains simple (unqualified) full (with template suffix) string name of variable, function, macro. // Obtains raw name of variable, function, macro.
#define NAMEOF_FULL(...) []() constexpr noexcept { \ #define NAMEOF_RAW(...) []() constexpr noexcept { \
::std::void_t<decltype(__VA_ARGS__)>(); \ ::std::void_t<decltype(__VA_ARGS__)>(); \
constexpr auto __name = ::nameof::detail::pretty_name(#__VA_ARGS__, false); \ constexpr auto _name = ::nameof::string_view{#__VA_ARGS__}; \
static_assert(__name.size() > 0, "Expression does not have a name."); \ static_assert(_name.size() > 0, "Expression does not have a name."); \
constexpr auto __size = __name.size(); \ constexpr auto _size = _name.size(); \
constexpr auto __nameof_full = ::nameof::cstring<__size>{__name}; \ constexpr auto _nameof_raw = ::nameof::cstring<_size>{_name}; \
return __nameof_full; }() return _nameof_raw; }()
// Obtains raw string name of variable, function, macro. // Obtains name of enum variable.
#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; }()
// Obtains simple (unqualified) string name of enum variable.
#define NAMEOF_ENUM(...) ::nameof::nameof_enum<::std::decay_t<decltype(__VA_ARGS__)>>(__VA_ARGS__) #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. // 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__>() #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__) #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__>() #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__)>() #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__>() #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__)>() #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__>() #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__)>() #define NAMEOF_SHORT_TYPE_EXPR(...) ::nameof::nameof_short_type<decltype(__VA_ARGS__)>()
// Obtains string name of type, using RTTI. // Obtains type name, with reference and cv-qualifiers, using RTTI.
#define NAMEOF_TYPE_RTTI(...) ::nameof::detail::demangle(typeid(__VA_ARGS__).name()) #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__) #if defined(__clang__)
# pragma clang diagnostic pop # pragma clang diagnostic pop

View file

@ -30,6 +30,12 @@
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#ifdef NDEBUG
# define NAMEOF_DEBUG_REQUIRE(...) REQUIRE(__VA_ARGS__)
#else
# define NAMEOF_DEBUG_REQUIRE(...)
#endif
struct SomeStruct { struct SomeStruct {
int somefield = 0; int somefield = 0;
@ -93,15 +99,18 @@ enum class BigFlags : std::uint64_t {
D = (static_cast<std::uint64_t>(0x1) << 63), D = (static_cast<std::uint64_t>(0x1) << 63),
}; };
namespace nameof {
template <> 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_assert(std::is_enum_v<number>, "nameof::enum_range<number> requires enum type.");
static constexpr int min = 100; static constexpr int min = 100;
static constexpr int max = 300; static constexpr int max = 300;
static_assert(max > min, "nameof::enum_range<number> requires max > min."); 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; SomeStruct struct_var;
Long othervar; 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)."); 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") { TEST_CASE("nameof_enum") {
SECTION("automatic storage") { SECTION("automatic storage") {
constexpr Color cr = Color::RED; constexpr Color cr = Color::RED;
@ -315,15 +260,15 @@ TEST_CASE("nameof_enum") {
REQUIRE(cr_name == "RED"); REQUIRE(cr_name == "RED");
REQUIRE(nameof::nameof_enum(Color::BLUE) == "BLUE"); REQUIRE(nameof::nameof_enum(Color::BLUE) == "BLUE");
REQUIRE(nameof::nameof_enum(cm[1]) == "GREEN"); 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 Numbers no = Numbers::one;
constexpr auto no_name = nameof::nameof_enum(no); constexpr auto no_name = nameof::nameof_enum(no);
REQUIRE(no_name == "one"); REQUIRE(no_name == "one");
REQUIRE(nameof::nameof_enum(Numbers::two) == "two"); REQUIRE(nameof::nameof_enum(Numbers::two) == "two");
REQUIRE(nameof::nameof_enum(Numbers::three) == "three"); REQUIRE(nameof::nameof_enum(Numbers::three) == "three");
REQUIRE(nameof::nameof_enum(Numbers::many).empty()); NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(Numbers::many).empty());
REQUIRE(nameof::nameof_enum(static_cast<Numbers>(0)).empty()); NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Numbers>(0)).empty());
constexpr Directions dr = Directions::Right; constexpr Directions dr = Directions::Right;
constexpr auto dr_name = nameof::nameof_enum(dr); constexpr auto dr_name = nameof::nameof_enum(dr);
@ -331,15 +276,15 @@ TEST_CASE("nameof_enum") {
REQUIRE(nameof::nameof_enum(Directions::Down) == "Down"); REQUIRE(nameof::nameof_enum(Directions::Down) == "Down");
REQUIRE(dr_name == "Right"); REQUIRE(dr_name == "Right");
REQUIRE(nameof::nameof_enum(Directions::Left) == "Left"); 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 number nt = number::three;
constexpr auto nt_name = nameof::nameof_enum(nt); constexpr auto nt_name = nameof::nameof_enum(nt);
REQUIRE(nameof::nameof_enum(number::one) == "one"); REQUIRE(nameof::nameof_enum(number::one) == "one");
REQUIRE(nameof::nameof_enum(number::two) == "two"); REQUIRE(nameof::nameof_enum(number::two) == "two");
REQUIRE(nt_name == "three"); REQUIRE(nt_name == "three");
REQUIRE(nameof::nameof_enum(number::four).empty()); NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(number::four).empty());
REQUIRE(nameof::nameof_enum(static_cast<number>(0)).empty()); NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<number>(0)).empty());
} }
SECTION("static storage") { SECTION("static storage") {
@ -380,11 +325,11 @@ TEST_CASE("nameof_enum_flag") {
REQUIRE(af_name == "HasClaws"); REQUIRE(af_name == "HasClaws");
REQUIRE(nameof::nameof_enum_flag(AnimalFlags::EatsFish) == "EatsFish"); REQUIRE(nameof::nameof_enum_flag(AnimalFlags::EatsFish) == "EatsFish");
REQUIRE(nameof::nameof_enum_flag(afm[1]) == "CanFly"); 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)) == "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 | 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>(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; constexpr BigFlags bf = BigFlags::A;
auto bf_name = nameof::nameof_enum_flag(bf); auto bf_name = nameof::nameof_enum_flag(bf);
@ -392,15 +337,79 @@ TEST_CASE("nameof_enum_flag") {
REQUIRE(bf_name == "A"); REQUIRE(bf_name == "A");
REQUIRE(nameof::nameof_enum_flag(BigFlags::C) == "C"); REQUIRE(nameof::nameof_enum_flag(BigFlags::C) == "C");
REQUIRE(nameof::nameof_enum_flag(bfm[1]) == "B"); REQUIRE(nameof::nameof_enum_flag(bfm[1]) == "B");
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(0)).empty()); NAMEOF_DEBUG_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>(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))) == "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 | (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>(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>((static_cast<std::uint64_t>(0x1) << 63) | 1)) == "A|D");
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(2)).empty()); NAMEOF_DEBUG_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>((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") { 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(afm[1]) == "CanFly");
REQUIRE(NAMEOF_ENUM_FLAG(AnimalFlags::EatsFish) == "EatsFish"); REQUIRE(NAMEOF_ENUM_FLAG(AnimalFlags::EatsFish) == "EatsFish");
REQUIRE(NAMEOF_ENUM_FLAG(AnimalFlags::Endangered) == "Endangered"); 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)) == "HasClaws|CanFly");
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 2 | 4)) == "HasClaws|CanFly|EatsFish"); 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>(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; constexpr BigFlags bf = BigFlags::A;
auto bf_name = NAMEOF_ENUM_FLAG(bf); 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(bfm[1]) == "B");
REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::C) == "C"); REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::C) == "C");
REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::D) == "D"); REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::D) == "D");
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(0)).empty()); NAMEOF_DEBUG_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>(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))) == "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>(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>((static_cast<std::uint64_t>(0x1) << 63) | 1)) == "A|D");
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(2)).empty()); NAMEOF_DEBUG_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>((static_cast<std::uint64_t>(0x1) << 63) | 2)).empty());
} }
#endif #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)."); 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") { TEST_CASE("nameof::nameof_type") {
constexpr auto type_name = NAMEOF_FULL_TYPE_EXPR(struct_var); constexpr auto type_name = nameof::nameof_type<decltype(struct_var)>();
#if defined(__clang__) #if defined(__clang__)
REQUIRE(type_name == "SomeStruct"); REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct *"); REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_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::nameof_type<decltype(othervar)>() == "Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL"); REQUIRE(nameof::nameof_type<Long>() == "Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int"); REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color"); REQUIRE(nameof::nameof_type<Color>() == "Color");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int> &&");
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
REQUIRE(type_name == "struct SomeStruct"); REQUIRE(type_name == "struct SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "struct SomeStruct *"); REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "struct SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_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::nameof_type<decltype(othervar)>() == "struct Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "struct Long::LL"); REQUIRE(nameof::nameof_type<Long>() == "struct Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int"); REQUIRE(nameof::nameof_type<Long::LL>() == "struct Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "enum Color"); REQUIRE(nameof::nameof_type<Color>() == "enum Color");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int> const &&");
#elif defined(__GNUC__) #elif defined(__GNUC__)
REQUIRE(type_name == "SomeStruct"); REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct*"); REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_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::nameof_type<decltype(othervar)>() == "Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL"); REQUIRE(nameof::nameof_type<Long>() == "Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int"); REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color"); REQUIRE(nameof::nameof_type<Color>() == "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");
#endif #endif
} }
@ -598,51 +560,22 @@ TEST_CASE("nameof::nameof_full_type") {
#endif #endif
} }
TEST_CASE("NAMEOF_TYPE_EXPR") { TEST_CASE("nameof::nameof_short_type") {
constexpr auto type_name = NAMEOF_TYPE_EXPR(struct_var); constexpr auto type_name = nameof::nameof_short_type<decltype(struct_var)>();
#if defined(__clang__)
REQUIRE(type_name == "SomeStruct"); REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct *"); REQUIRE(nameof::nameof_short_type<decltype(ref_s)>() == "SomeStruct");
REQUIRE(NAMEOF_TYPE_EXPR(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::nameof_short_type<decltype(othervar)>() == "Long");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL"); REQUIRE(nameof::nameof_short_type<Long>() == "Long");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int"); REQUIRE(nameof::nameof_short_type<Long::LL>() == "LL");
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color"); REQUIRE(nameof::nameof_short_type<Color>() == "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
} }
TEST_CASE("NAMEOF_TYPE") { TEST_CASE("NAMEOF_TYPE") {
@ -701,72 +634,248 @@ TEST_CASE("NAMEOF_TYPE") {
#endif #endif
} }
TEST_CASE("nameof::nameof_type") { TEST_CASE("NAMEOF_TYPE_EXPR") {
constexpr auto type_name = nameof::nameof_type<decltype(struct_var)>(); constexpr auto type_name = NAMEOF_TYPE_EXPR(struct_var);
#if defined(__clang__) #if defined(__clang__)
REQUIRE(type_name == "SomeStruct"); REQUIRE(type_name == "SomeStruct");
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct *"); REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct *");
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct"); REQUIRE(NAMEOF_TYPE_EXPR(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::nameof_type<SomeClass<int>>() == "SomeClass<int>"); REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int> *");
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long"); REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
REQUIRE(nameof::nameof_type<Long>() == "Long"); REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(nameof::nameof_type<Long::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) #elif defined(_MSC_VER)
REQUIRE(type_name == "struct SomeStruct"); REQUIRE(type_name == "struct SomeStruct");
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "struct SomeStruct *"); REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "struct SomeStruct"); REQUIRE(NAMEOF_TYPE_EXPR(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::nameof_type<SomeClass<int>>() == "class SomeClass<int>"); REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "class SomeClass<int> const volatile *");
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "struct Long"); REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "struct Long");
REQUIRE(nameof::nameof_type<Long>() == "struct Long"); REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "struct Long::LL");
REQUIRE(nameof::nameof_type<Long::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__) #elif defined(__GNUC__)
REQUIRE(type_name == "SomeStruct"); REQUIRE(type_name == "SomeStruct");
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct*"); REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct*");
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct"); REQUIRE(NAMEOF_TYPE_EXPR(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::nameof_type<SomeClass<int>>() == "SomeClass<int>"); REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int>*");
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long"); REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
REQUIRE(nameof::nameof_type<Long>() == "Long"); REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(nameof::nameof_type<Long::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 #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 #endif
#if defined(NAMEOF_TYPE_RTTI_SUPPORTED) && NAMEOF_TYPE_RTTI_SUPPORTED #if defined(NAMEOF_TYPE_RTTI_SUPPORTED) && NAMEOF_TYPE_RTTI_SUPPORTED
TEST_CASE("NAMEOF_TYPE_RTTI") { TEST_CASE("NAMEOF_TYPE_RTTI") {
#if defined(__clang__) TestRtti::Base* ptr = new TestRtti::Derived();
REQUIRE(NAMEOF_TYPE_RTTI(Color) == "Color"); 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) #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__) #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 #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 #endif