diff --git a/CMakeLists.txt b/CMakeLists.txt index 968fbd2..cc71744 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.6) -project(nameof VERSION "0.6.1" LANGUAGES CXX) +project(nameof VERSION "0.6.2" LANGUAGES CXX) option(NAMEOF_OPT_BUILD_EXAMPLES "Build nameof examples" ON) option(NAMEOF_OPT_BUILD_TESTS "Build and perform nameof tests" ON) diff --git a/README.md b/README.md index 94af64e..2baaee6 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ master |[![Build Status](https://travis-ci.org/Neargye/nameof.svg?branch=master) ## What is Nameof? -Header-only C++17 library provides nameof macros and functions to obtain the simple name of variable, type, function, macro, and enum. +Header-only C++17 library provides nameof macros and functions to obtain simple name of variable, type, function, macro, and enum. Before, you had to use string literals to refer to definitions, which is brittle when renaming code elements because tools do not know to check these string literals. @@ -56,9 +56,9 @@ static_assert("foo" == cx_name); * Name of enum ```cpp // Name of enum -const auto c = Color::RED; +auto c = Color::RED; NAMEOF_ENUM(c) -> "RED" -// Name of enum function +// Name of enum nameof::nameof_enum(c) -> "RED" constexpr auto cx_name = NAMEOF_ENUM(c); @@ -71,9 +71,9 @@ static_assert("RED" == cx_name); NAMEOF_TYPE(Color::RED) -> "Color" // Name of type NAMEOF_TYPE_T(int) -> "int" -// Name of variable type function +// Name of variable type nameof::nameof_type(Color::RED) -> "Color" -// Name of type function +// Name of type nameof::nameof_type -> "int" constexpr auto cx_name = NAMEOF_TYPE(Color::RED); @@ -82,6 +82,7 @@ static_assert("Color" == cx_name); * Name of macro ```cpp +// Name of macro NAMEOF(__LINE__) -> "__LINE__" constexpr auto cx_name = NAMEOF(__LINE__); @@ -92,12 +93,13 @@ static_assert("__LINE__" == cx_name); * Nameof return std::string_view. -* The argument expression identifies a code definition, but it is never evaluated. +* The argument expression identifies code definition, but it is never evaluated. * If you need raw fully-qualified name, use NAMEOF_RAW. ```cpp NAMEOF_RAW(somevar.somefield) -> "somevar.somefield" NAMEOF_RAW(&SomeStruct::SomeMethod) -> "&SomeStruct::SomeMethod" +NAMEOF_RAW(std::string) -> "std::string" ``` * NAMEOF_ENUM does not work on the GCC. @@ -122,6 +124,6 @@ You should add required file [nameof.hpp](include/nameof.hpp). * Clang/LLVM >= 5 * MSVC >= 15.3 / Visual Studio 2017 * Xcode >= 9 -* GCC >= 7 (NAMEOF_ENUM not support) +* GCC >= 7 ## Licensed under the [MIT License](LICENSE) diff --git a/example/example.cpp b/example/example.cpp index d47abd0..cfbdfae 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -130,6 +130,7 @@ int main() { std::cout << NAMEOF_RAW(__LINE__) << std::endl; // __LINE__ std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // structvar.somefield std::cout << NAMEOF_RAW(&SomeStruct::SomeMethod1) << std::endl; // &SomeStruct::SomeMethod1 + std::cout << NAMEOF_RAW(const SomeClass volatile *) << std::endl; // const SomeClass volatile * // Some more example. diff --git a/include/nameof.hpp b/include/nameof.hpp index d8623bf..1289f5b 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -5,7 +5,7 @@ // | |\ | (_| | | | | | | __/ (_) | | | |____|_| |_| // |_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____| // https://github.com/Neargye/nameof -// vesion 0.6.1 +// vesion 0.6.2 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT @@ -44,19 +44,19 @@ namespace nameof { namespace detail { template -struct identity { +struct identity final { using type = T; }; -constexpr bool is_name_char(char s) noexcept { +[[nodiscard]] constexpr bool is_name_char(char s) noexcept { return (s >= '0' && s <= '9') || (s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || s == '_'; } -constexpr bool is_bracket_char(char s) noexcept { +[[nodiscard]] constexpr bool is_bracket_char(char s) noexcept { return s == ')' || s == '}' || s == '>' || s == '(' || s == '{' || s == '<'; } -constexpr std::string_view pretty_name(std::string_view name, bool with_suffix) noexcept { +[[nodiscard]] constexpr std::string_view pretty_name(std::string_view name, bool with_suffix) noexcept { for (std::size_t i = name.size(), h = 0, s = 0; i > 0; --i) { if (h == 0 && !is_name_char(name[i - 1]) && !is_bracket_char(name[i - 1])) { ++s; @@ -114,7 +114,7 @@ constexpr std::string_view pretty_name(std::string_view name, bool with_suffix) } template -constexpr int nameof_enum_impl_() noexcept { +[[nodiscard]] constexpr int nameof_enum_impl_() noexcept { #if defined(__clang__) return sizeof(__PRETTY_FUNCTION__) - sizeof("int nameof::detail::nameof_enum_impl_() [E = ") - sizeof("]") + 1; #elif defined(__GNUC__) @@ -127,7 +127,7 @@ constexpr int nameof_enum_impl_() noexcept { } template -constexpr std::string_view nameof_enum_impl() noexcept { +[[nodiscard]] constexpr std::string_view nameof_enum_impl() noexcept { #if defined(__clang__) const auto str = __PRETTY_FUNCTION__; const auto size = sizeof(__PRETTY_FUNCTION__) - 1; @@ -152,8 +152,8 @@ constexpr std::string_view nameof_enum_impl() noexcept { } template -struct nameof_enum_t { - constexpr std::string_view operator()(int value) const noexcept { +struct nameof_enum_t final { + [[nodiscard]] constexpr std::string_view operator()(int value) const noexcept { switch (value - V) { case 0: return nameof_enum_impl(); @@ -178,13 +178,13 @@ struct nameof_enum_t { }; template -struct nameof_enum_t { - constexpr std::string_view operator()(int) const noexcept { +struct nameof_enum_t final { + [[nodiscard]] constexpr std::string_view operator()(int) const noexcept { return {"nameof_enum::out_of_range"}; } }; -constexpr std::string_view nameof_type_impl_(std::string_view name) noexcept { +[[nodiscard]] constexpr std::string_view nameof_type_impl_(std::string_view name) noexcept { #if defined(_MSC_VER) if (name.size() > sizeof("enum") && name[0] == 'e' && name[1] == 'n' && name[2] == 'u' && name[3] == 'm' && name[4] == ' ') { name.remove_prefix(sizeof("enum")); @@ -204,7 +204,7 @@ constexpr std::string_view nameof_type_impl_(std::string_view name) noexcept { } template -constexpr std::string_view nameof_type_impl() noexcept { +[[nodiscard]] constexpr std::string_view nameof_type_impl() noexcept { #if defined(__clang__) const auto str = __PRETTY_FUNCTION__; const auto size = sizeof(__PRETTY_FUNCTION__) - 1; @@ -229,49 +229,48 @@ constexpr std::string_view nameof_type_impl() noexcept { } template >> -constexpr std::string_view nameof_impl(std::string_view name, bool with_suffix) noexcept { +[[nodiscard]] constexpr std::string_view nameof_impl(std::string_view name, bool with_suffix) noexcept { return detail::pretty_name(name, with_suffix); } -template -constexpr std::string_view nameof_raw_impl(std::string_view name) noexcept { +[[nodiscard]] constexpr std::string_view nameof_raw_impl(std::string_view name) noexcept { return name; } } // namespace detail template >>> -constexpr std::string_view nameof_enum(T value) noexcept { +[[nodiscard]] constexpr std::string_view nameof_enum(T value) noexcept { constexpr auto s = std::is_signed_v>>; return detail::nameof_enum_t, s ? -NAMEOF_ENUM_MAX_SEARCH_DEPTH : 0>{}(static_cast(value)); } template -constexpr std::string_view nameof_type() noexcept { +[[nodiscard]] constexpr std::string_view nameof_type() noexcept { return detail::nameof_type_impl>(); } template -constexpr std::string_view nameof_type(T) noexcept { +[[nodiscard]] constexpr std::string_view nameof_type(T) noexcept { return nameof_type(); } } // namespace nameof -// Used to obtain the simple (unqualified) string name of variable, function, enum, macro. +// NAMEOF used to obtain the simple (unqualified) string name of variable, function, enum, macro. #define NAMEOF(...) ::nameof::detail::nameof_impl(#__VA_ARGS__, false) -// Used to obtain the full string name of variable, function, enum, macro. +// NAMEOF_FULL used to obtain the full string name of variable, function, enum, macro. #define NAMEOF_FULL(...) ::nameof::detail::nameof_impl(#__VA_ARGS__, true) -// Used to obtain the raw string name of variable, function, enum, macro. -#define NAMEOF_RAW(...) ::nameof::detail::nameof_raw_impl(#__VA_ARGS__) - -// Used to obtain the simple (unqualified) string name of enum variable. +// NAMEOF_ENUM used to obtain the simple (unqualified) string name of enum variable. #define NAMEOF_ENUM(...) ::nameof::nameof_enum(__VA_ARGS__) -// Used to obtain the string name of variable type. +// NAMEOF_TYPE used to obtain the string name of variable type. #define NAMEOF_TYPE(...) ::nameof::nameof_type() -// Used to obtain the string name of type. +// NAMEOF_TYPE_T used to obtain the string name of type. #define NAMEOF_TYPE_T(...) ::nameof::nameof_type<__VA_ARGS__>() + +// NAMEOF_RAW used to obtain the raw string name of variable, function, enum, macro. +#define NAMEOF_RAW(...) ::nameof::detail::nameof_raw_impl(#__VA_ARGS__) diff --git a/test/test.cpp b/test/test.cpp index 0dab160..78a87c6 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -201,6 +201,12 @@ TEST_CASE("NAMEOF_RAW") { REQUIRE(NAMEOF_RAW(__LINE__) == "__LINE__"); REQUIRE(NAMEOF_RAW(__FILE__) == "__FILE__"); } + + SECTION("type") { + REQUIRE(NAMEOF_RAW(const SomeStruct volatile *) == "const SomeStruct volatile *"); + REQUIRE(NAMEOF_RAW(SomeClass) == "SomeClass"); + REQUIRE(NAMEOF_RAW(decltype(othervar)) == "decltype(othervar)"); + } } TEST_CASE("NAMEOF_ENUM") {