improve nameof
This commit is contained in:
parent
b236173ad9
commit
e25503192f
4 changed files with 38 additions and 48 deletions
|
@ -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.
|
* If you need of raw fully-qualified name, use NAMEOF_RAW.
|
||||||
```cpp
|
```cpp
|
||||||
NAMEOF_RAW(somevar.somefield) -> "somevar.somefield"
|
NAMEOF_RAW(somevar.somefield) -> "somevar.somefield"
|
||||||
NAMEOF_RAW(&SomeStruct::SomeMethod) -> "&SomeStruct::SomeMethod"
|
NAMEOF_RAW(&some_class::some_method<int>) -> "&some_class::some_method<int>"
|
||||||
NAMEOF_RAW(const SomeClass<int> volatile *) -> "const SomeClass<int> volatile *"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
* Spaces and Tabs ignored
|
* Spaces and Tabs ignored
|
||||||
|
|
|
@ -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((&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(othervar.ll.field) << std::endl; // field
|
||||||
|
std::cout << NAMEOF(ptrvar) << std::endl; // 'ptrvar'
|
||||||
|
|
||||||
// Function name.
|
// Function name.
|
||||||
std::cout << NAMEOF(&SomeStruct::SomeMethod1) << std::endl; // SomeMethod1
|
std::cout << NAMEOF(&SomeStruct::SomeMethod1) << std::endl; // SomeMethod1
|
||||||
|
@ -120,7 +121,7 @@ int main() {
|
||||||
// Type name.
|
// Type name.
|
||||||
std::cout << NAMEOF_VAR_TYPE(structvar) << std::endl; // SomeStruct
|
std::cout << NAMEOF_VAR_TYPE(structvar) << std::endl; // SomeStruct
|
||||||
std::cout << nameof::nameof_type<decltype(structvar)>() << std::endl; // SomeStruct
|
std::cout << nameof::nameof_type<decltype(structvar)>() << std::endl; // SomeStruct
|
||||||
std::cout << NAMEOF_VAR_TYPE(SomeClass<int>{}) << std::endl; // SomeClass
|
std::cout << NAMEOF_VAR_TYPE(SomeClass<int>{}) << std::endl; // SomeClass<int>
|
||||||
std::cout << NAMEOF_VAR_TYPE(othervar.ll) << std::endl; // Long::LL
|
std::cout << NAMEOF_VAR_TYPE(othervar.ll) << std::endl; // Long::LL
|
||||||
std::cout << NAMEOF_VAR_TYPE(std::declval<const SomeClass<int>>()) << std::endl; // const SomeClass<int> &&
|
std::cout << NAMEOF_VAR_TYPE(std::declval<const SomeClass<int>>()) << std::endl; // const SomeClass<int> &&
|
||||||
|
|
||||||
|
@ -135,7 +136,6 @@ int main() {
|
||||||
// Raw name.
|
// Raw name.
|
||||||
std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // structvar.somefield
|
std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // structvar.somefield
|
||||||
std::cout << NAMEOF_RAW(&SomeStruct::SomeMethod1) << std::endl; // &SomeStruct::SomeMethod1
|
std::cout << NAMEOF_RAW(&SomeStruct::SomeMethod1) << std::endl; // &SomeStruct::SomeMethod1
|
||||||
std::cout << NAMEOF_RAW(const SomeClass<int> volatile *) << std::endl; // const SomeClass<int> volatile *
|
|
||||||
|
|
||||||
// Some more complex example.
|
// Some more complex example.
|
||||||
|
|
||||||
|
@ -158,30 +158,20 @@ int main() {
|
||||||
/* Remarks */
|
/* Remarks */
|
||||||
#if 0
|
#if 0
|
||||||
// This expression does not have name.
|
// 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.0) << std::endl; // ''
|
||||||
std::cout << NAMEOF(42.f) << std::endl; // 'f'
|
|
||||||
std::cout << NAMEOF(42) << std::endl; // ''
|
std::cout << NAMEOF(42) << std::endl; // ''
|
||||||
std::cout << NAMEOF(42.0_deg) << std::endl; // ''
|
std::cout << NAMEOF(42.0_deg) << std::endl; // ''
|
||||||
std::cout << NAMEOF(std::string()) << std::endl; // 'string'
|
std::cout << NAMEOF((structvar)) << std::endl; // ''
|
||||||
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((SomeMethod4<int, float>)(1.0f)) << std::endl; // ''
|
std::cout << NAMEOF((SomeMethod4<int, float>)(1.0f)) << std::endl; // ''
|
||||||
std::cout << NAMEOF(42, 42, 42) << std::endl; // ''
|
std::cout << NAMEOF(42, 42, 42) << std::endl; // ''
|
||||||
#endif
|
std::cout << NAMEOF(42 + 42) << std::endl; // ''
|
||||||
|
std::cout << NAMEOF("Bad case"_string) << std::endl; // ''
|
||||||
#if 0
|
std::cout << NAMEOF("Bad case") << std::endl; // ''
|
||||||
// This expression does not have name and not compilation.
|
std::cout << NAMEOF("somevar.somefield") << std::endl; // ''
|
||||||
std::cout << NAMEOF("Bad case") << std::endl;
|
std::cout << NAMEOF(42.f) << std::endl; // ''
|
||||||
std::cout << NAMEOF("somevar.somefield") << std::endl;
|
std::cout << NAMEOF(structvar.somefield++) << std::endl; // ''
|
||||||
std::cout << NAMEOF(std::basic_string<char>) << std::endl;
|
std::cout << NAMEOF(std::string{"test"}) << 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;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -61,22 +61,13 @@ struct identity final {
|
||||||
return (!front && c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
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 {
|
[[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) {
|
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])) {
|
if (name[i - 1] == ')') {
|
||||||
++s;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name[i - 1] == ')' || name[i - 1] == '}') {
|
|
||||||
++h;
|
++h;
|
||||||
++s;
|
++s;
|
||||||
continue;
|
continue;
|
||||||
} else if (name[i - 1] == '(' || name[i - 1] == '{') {
|
} else if (name[i - 1] == '(') {
|
||||||
--h;
|
--h;
|
||||||
++s;
|
++s;
|
||||||
continue;
|
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;
|
std::size_t s = 0;
|
||||||
for (std::size_t i = name.size(), h = 0; i > 0; --i) {
|
for (std::size_t i = name.size(), h = 0; i > 0; --i) {
|
||||||
if (name[i - 1] == '>') {
|
if (name[i - 1] == '>') {
|
||||||
|
@ -122,7 +117,7 @@ struct identity final {
|
||||||
if (name.length() > 0 && is_name_char(name.front(), true)) {
|
if (name.length() > 0 && is_name_char(name.front(), true)) {
|
||||||
return name;
|
return name;
|
||||||
} else {
|
} else {
|
||||||
return {}; // Does not have name.
|
return {}; // Invalid name.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +178,19 @@ template <typename E, E V>
|
||||||
|
|
||||||
#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 9) || defined(_MSC_VER)
|
#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 9) || defined(_MSC_VER)
|
||||||
name.remove_suffix(suffix);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,11 +233,12 @@ struct nameof_enum_impl_t<E, NAMEOF_ENUM_RANGE> final {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename = std::enable_if_t<!std::is_reference_v<T>>>
|
template <typename T>
|
||||||
[[nodiscard]] constexpr std::string_view nameof_impl(std::string_view name, bool with_template_suffix) noexcept {
|
[[nodiscard]] constexpr std::string_view nameof_impl(std::string_view name, bool with_template_suffix) noexcept {
|
||||||
return pretty_name(name, with_template_suffix);
|
return pretty_name(name, with_template_suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
[[nodiscard]] 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;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -268,6 +276,9 @@ template <typename T>
|
||||||
// NAMEOF_FULL used to obtain the simple (unqualified) full (with template suffix) string name of variable, function, enum, macro.
|
// 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<decltype(__VA_ARGS__)>(#__VA_ARGS__, true)
|
#define NAMEOF_FULL(...) ::nameof::detail::nameof_impl<decltype(__VA_ARGS__)>(#__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<decltype(__VA_ARGS__)>(#__VA_ARGS__)
|
||||||
|
|
||||||
// NAMEOF_ENUM used to obtain the simple (unqualified) string enum name of enum variable.
|
// NAMEOF_ENUM used to obtain the simple (unqualified) string enum name of enum variable.
|
||||||
#define NAMEOF_ENUM(...) ::nameof::nameof_enum<decltype(__VA_ARGS__)>(__VA_ARGS__)
|
#define NAMEOF_ENUM(...) ::nameof::nameof_enum<decltype(__VA_ARGS__)>(__VA_ARGS__)
|
||||||
|
|
||||||
|
@ -279,6 +290,3 @@ template <typename T>
|
||||||
|
|
||||||
// NAMEOF_VAR_TYPE used to obtain the string name of variable type.
|
// NAMEOF_VAR_TYPE used to obtain the string name of variable type.
|
||||||
#define NAMEOF_VAR_TYPE(...) ::nameof::nameof_type<decltype(__VA_ARGS__)>()
|
#define NAMEOF_VAR_TYPE(...) ::nameof::nameof_type<decltype(__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__)
|
|
||||||
|
|
|
@ -93,7 +93,6 @@ TEST_CASE("NAMEOF") {
|
||||||
|
|
||||||
SECTION("member") {
|
SECTION("member") {
|
||||||
REQUIRE(NAMEOF(struct_var.somefield) == "somefield");
|
REQUIRE(NAMEOF(struct_var.somefield) == "somefield");
|
||||||
REQUIRE(NAMEOF(struct_var.somefield++) == "somefield");
|
|
||||||
REQUIRE(NAMEOF((&struct_var)->somefield) == "somefield");
|
REQUIRE(NAMEOF((&struct_var)->somefield) == "somefield");
|
||||||
REQUIRE(NAMEOF(othervar.ll.field) == "field");
|
REQUIRE(NAMEOF(othervar.ll.field) == "field");
|
||||||
}
|
}
|
||||||
|
@ -129,7 +128,6 @@ TEST_CASE("NAMEOF_FULL") {
|
||||||
|
|
||||||
SECTION("member") {
|
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((&struct_var)->somefield) == "somefield");
|
REQUIRE(NAMEOF_FULL((&struct_var)->somefield) == "somefield");
|
||||||
REQUIRE(NAMEOF_FULL(othervar.ll.field) == "field");
|
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(::struct_var) == "::struct_var");
|
||||||
REQUIRE(NAMEOF_RAW(ptr_s) == "ptr_s");
|
REQUIRE(NAMEOF_RAW(ptr_s) == "ptr_s");
|
||||||
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") {
|
SECTION("member") {
|
||||||
|
@ -202,12 +201,6 @@ TEST_CASE("NAMEOF_RAW") {
|
||||||
REQUIRE(NAMEOF_RAW(__LINE__) == "__LINE__");
|
REQUIRE(NAMEOF_RAW(__LINE__) == "__LINE__");
|
||||||
REQUIRE(NAMEOF_RAW(__FILE__) == "__FILE__");
|
REQUIRE(NAMEOF_RAW(__FILE__) == "__FILE__");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("type") {
|
|
||||||
REQUIRE(NAMEOF_RAW(const SomeStruct volatile *) == "const SomeStruct volatile *");
|
|
||||||
REQUIRE(NAMEOF_RAW(SomeClass<int>) == "SomeClass<int>");
|
|
||||||
REQUIRE(NAMEOF_RAW(decltype(othervar)) == "decltype(othervar)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NAMEOF_ENUM") {
|
TEST_CASE("NAMEOF_ENUM") {
|
||||||
|
|
Loading…
Reference in a new issue