diff --git a/README.md b/README.md index e5a1653..02e6598 100644 --- a/README.md +++ b/README.md @@ -102,8 +102,7 @@ Header-only C++17 library provides nameof macros and functions to obtain simple * If you need of raw fully-qualified name, use NAMEOF_RAW. ```cpp NAMEOF_RAW(somevar.somefield) -> "somevar.somefield" - NAMEOF_RAW(&SomeStruct::SomeMethod) -> "&SomeStruct::SomeMethod" - NAMEOF_RAW(const SomeClass volatile *) -> "const SomeClass volatile *" + NAMEOF_RAW(&some_class::some_method) -> "&some_class::some_method" ``` * Spaces and Tabs ignored diff --git a/example/example.cpp b/example/example.cpp index 6fddf62..d7786a2 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -102,6 +102,7 @@ int main() { std::cout << NAMEOF(structvar.somefield) << std::endl; // somefield std::cout << NAMEOF((&structvar)->somefield) << std::endl; // somefield std::cout << NAMEOF(othervar.ll.field) << std::endl; // field + std::cout << NAMEOF(ptrvar) << std::endl; // 'ptrvar' // Function name. std::cout << NAMEOF(&SomeStruct::SomeMethod1) << std::endl; // SomeMethod1 @@ -120,7 +121,7 @@ int main() { // Type name. std::cout << NAMEOF_VAR_TYPE(structvar) << std::endl; // SomeStruct std::cout << nameof::nameof_type() << std::endl; // SomeStruct - std::cout << NAMEOF_VAR_TYPE(SomeClass{}) << std::endl; // SomeClass + std::cout << NAMEOF_VAR_TYPE(SomeClass{}) << std::endl; // SomeClass std::cout << NAMEOF_VAR_TYPE(othervar.ll) << std::endl; // Long::LL std::cout << NAMEOF_VAR_TYPE(std::declval>()) << std::endl; // const SomeClass && @@ -135,7 +136,6 @@ int main() { // Raw name. 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 complex example. @@ -158,30 +158,20 @@ int main() { /* Remarks */ #if 0 // This expression does not have name. - std::cout << NAMEOF("Bad case"_string) << std::endl; // '_string' + std::cout << NAMEOF(ptrvar[0]) << std::endl; // '' std::cout << NAMEOF(42.0) << std::endl; // '' - std::cout << NAMEOF(42.f) << std::endl; // 'f' std::cout << NAMEOF(42) << std::endl; // '' std::cout << NAMEOF(42.0_deg) << std::endl; // '' - std::cout << NAMEOF(std::string()) << std::endl; // 'string' - std::cout << NAMEOF(std::string{}) << std::endl; // 'string' - std::cout << NAMEOF(std::string{"test"}) << std::endl; // 'string' - std::cout << NAMEOF(structvar.somefield + structvar.somefield) << std::endl; // ' somefield' - std::cout << NAMEOF(42 + 42) << std::endl; // '' + std::cout << NAMEOF((structvar)) << std::endl; // '' std::cout << NAMEOF((SomeMethod4)(1.0f)) << std::endl; // '' std::cout << NAMEOF(42, 42, 42) << std::endl; // '' -#endif - -#if 0 - // This expression does not have name and not compilation. - std::cout << NAMEOF("Bad case") << std::endl; - std::cout << NAMEOF("somevar.somefield") << std::endl; - std::cout << NAMEOF(std::basic_string) << std::endl; - std::cout << NAMEOF(ptrvar[0]) << std::endl; - std::cout << NAMEOF(std::cout << structvar << std::endl) << std::endl; - std::cout << NAMEOF(decltype(structvar)) << std::endl; - std::cout << NAMEOF(typeid(structvar)) << std::endl; - std::cout << NAMEOF((structvar)) << std::endl; + std::cout << NAMEOF(42 + 42) << std::endl; // '' + std::cout << NAMEOF("Bad case"_string) << std::endl; // '' + std::cout << NAMEOF("Bad case") << std::endl; // '' + std::cout << NAMEOF("somevar.somefield") << std::endl; // '' + std::cout << NAMEOF(42.f) << std::endl; // '' + std::cout << NAMEOF(structvar.somefield++) << std::endl; // '' + std::cout << NAMEOF(std::string{"test"}) << std::endl; // '' #endif return 0; diff --git a/include/nameof.hpp b/include/nameof.hpp index dc59215..ad391a8 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -61,22 +61,13 @@ struct identity final { return (!front && c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; } -[[nodiscard]] constexpr bool is_bracket_char(char c) noexcept { - return c == ')' || c == '}' || c == '>' || c == '(' || c == '{' || c == '<'; -} - [[nodiscard]] constexpr std::string_view pretty_name(std::string_view name, bool with_template_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], false) && !is_bracket_char(name[i - 1])) { - ++s; - continue; - } - - if (name[i - 1] == ')' || name[i - 1] == '}') { + if (name[i - 1] == ')') { ++h; ++s; continue; - } else if (name[i - 1] == '(' || name[i - 1] == '{') { + } else if (name[i - 1] == '(') { --h; ++s; continue; @@ -91,6 +82,10 @@ struct identity final { } } + if (name.length() > 0 && (name.front() == '"' || (name.front() >= '0' && name.front() <= '9') || name.back() == '"')) { + return {}; // Invalid name. + } + std::size_t s = 0; for (std::size_t i = name.size(), h = 0; i > 0; --i) { if (name[i - 1] == '>') { @@ -122,7 +117,7 @@ struct identity final { if (name.length() > 0 && is_name_char(name.front(), true)) { return name; } else { - return {}; // Does not have name. + return {}; // Invalid name. } } @@ -183,7 +178,19 @@ template #if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 9) || defined(_MSC_VER) name.remove_suffix(suffix); - return pretty_name(name, false); + for (std::size_t i = name.size(); i > 0; --i) { + if (!is_name_char(name[i - 1], false)) { + name.remove_prefix(i); + break; + } + } + + if (name.length() > 0 && is_name_char(name.front(), true)) { + return name; + } + else { + return {}; // Invalid enum name. + } #endif } @@ -226,11 +233,12 @@ struct nameof_enum_impl_t final { } }; -template >> +template [[nodiscard]] constexpr std::string_view nameof_impl(std::string_view name, bool with_template_suffix) noexcept { return pretty_name(name, with_template_suffix); } +template [[nodiscard]] constexpr std::string_view nameof_raw_impl(std::string_view name) noexcept { return name; } @@ -268,6 +276,9 @@ template // NAMEOF_FULL used to obtain the simple (unqualified) full (with template suffix) string name of variable, function, enum, macro. #define NAMEOF_FULL(...) ::nameof::detail::nameof_impl(#__VA_ARGS__, true) +// NAMEOF_RAW used to obtain the raw string name of variable, function, enum, macro. +#define NAMEOF_RAW(...) ::nameof::detail::nameof_raw_impl(#__VA_ARGS__) + // NAMEOF_ENUM used to obtain the simple (unqualified) string enum name of enum variable. #define NAMEOF_ENUM(...) ::nameof::nameof_enum(__VA_ARGS__) @@ -279,6 +290,3 @@ template // NAMEOF_VAR_TYPE used to obtain the string name of variable type. #define NAMEOF_VAR_TYPE(...) ::nameof::nameof_type() - -// 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 b5ebcd1..3378715 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -93,7 +93,6 @@ TEST_CASE("NAMEOF") { SECTION("member") { REQUIRE(NAMEOF(struct_var.somefield) == "somefield"); - REQUIRE(NAMEOF(struct_var.somefield++) == "somefield"); REQUIRE(NAMEOF((&struct_var)->somefield) == "somefield"); REQUIRE(NAMEOF(othervar.ll.field) == "field"); } @@ -129,7 +128,6 @@ TEST_CASE("NAMEOF_FULL") { SECTION("member") { REQUIRE(NAMEOF_FULL(struct_var.somefield) == "somefield"); - REQUIRE(NAMEOF_FULL(struct_var.somefield++) == "somefield"); REQUIRE(NAMEOF_FULL((&struct_var)->somefield) == "somefield"); REQUIRE(NAMEOF_FULL(othervar.ll.field) == "field"); } @@ -163,6 +161,7 @@ TEST_CASE("NAMEOF_RAW") { REQUIRE(NAMEOF_RAW(::struct_var) == "::struct_var"); REQUIRE(NAMEOF_RAW(ptr_s) == "ptr_s"); REQUIRE(NAMEOF_RAW(*ptr_s) == "*ptr_s"); + REQUIRE(NAMEOF_RAW(ptr_s[0]) == "ptr_s[0]"); } SECTION("member") { @@ -202,12 +201,6 @@ 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") {