From f6a6c5de10714202bda712dc94307d39ac8c6bc0 Mon Sep 17 00:00:00 2001 From: neargye Date: Mon, 26 Aug 2019 21:26:28 +0500 Subject: [PATCH] improve static_assert and come clean-up --- include/nameof.hpp | 71 +++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/include/nameof.hpp b/include/nameof.hpp index 385196c..fe82d4f 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -83,8 +83,21 @@ struct identity final { using type = T; }; -template -struct always_false final : std::false_type {}; +template +struct nameof_type_supported final +#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER) + : std::true_type {}; +#else + : std::false_type {}; +#endif + +template +struct nameof_enum_supported final +#if defined(__clang__) || defined(__GNUC__) && __GNUC__>= 9 || defined(_MSC_VER) + : std::true_type {}; +#else + : std::false_type {}; +#endif template using remove_cvref_t = std::remove_cv_t>; @@ -93,8 +106,8 @@ template using enable_if_enum_t = std::enable_if_t>, R>; template -[[nodiscard]] constexpr std::string_view nameof_impl(std::string_view name, bool remove_template_suffix = true) noexcept { - static_assert(std::is_void_v, "nameof::detail::nameof_impl requires void type."); +[[nodiscard]] constexpr std::string_view nameof(std::string_view name, bool remove_template_suffix = true) noexcept { + static_assert(std::is_void_v, "nameof::detail::nameof requires void type."); if (name.length() >= 1 && (name.front() == '"' || name.front() == '\'')) { return {}; // Narrow multibyte string literal. } else if (name.length() >= 2 && name[0] == 'R' && (name[1] == '"' || name[1] == '\'')) { @@ -174,52 +187,55 @@ template } template -[[nodiscard]] constexpr std::string_view nameof_raw_impl(std::string_view name) noexcept { - static_assert(std::is_void_v, "nameof::detail::nameof_raw_impl requires void type."); +[[nodiscard]] constexpr std::string_view nameof_raw(std::string_view name) noexcept { + static_assert(std::is_void_v, "nameof::detail::nameof_raw requires void type."); return name; } template -[[nodiscard]] constexpr auto nameof_enum_impl() noexcept { - static_assert(std::is_enum_v, "nameof::detail::nameof_enum_impl requires enum type."); +[[nodiscard]] constexpr auto n() noexcept { + static_assert(std::is_enum_v, "nameof::detail::nameof_enum requires enum type."); #if defined(__clang__) || defined(__GNUC__) && __GNUC__ >= 9 - return nameof_impl({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); + return nameof({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); #elif defined(_MSC_VER) - return nameof_impl({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); + return nameof({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); #else - static_assert(always_false{}, "nameof::nameof_enum: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); return std::string_view{}; // Unsupported compiler. #endif } template -[[nodiscard]] constexpr auto enum_names_impl(std::integer_sequence) noexcept { - static_assert(std::is_enum_v, "nameof::detail::enum_names_impl requires enum type."); +[[nodiscard]] constexpr auto enum_names(std::integer_sequence) noexcept { + static_assert(std::is_enum_v, "nameof::detail::enum_names requires enum type."); - return std::array{{nameof_enum_impl(I + O)>()...}}; + return std::array{{n(I + O)>()...}}; } template -[[nodiscard]] constexpr auto nameof_type_impl() noexcept { +[[nodiscard]] constexpr auto n() noexcept { #if defined(__clang__) - return std::string_view{__PRETTY_FUNCTION__ + 46, sizeof(__PRETTY_FUNCTION__) - 49}; + return std::string_view{__PRETTY_FUNCTION__ + 31, sizeof(__PRETTY_FUNCTION__) - 34}; #elif defined(__GNUC__) - return std::string_view{__PRETTY_FUNCTION__ + 61, sizeof(__PRETTY_FUNCTION__) - 64}; + return std::string_view{__PRETTY_FUNCTION__ + 46, sizeof(__PRETTY_FUNCTION__) - 49}; #elif defined(_MSC_VER) - return std::string_view{__FUNCSIG__ + 78, sizeof(__FUNCSIG__) - 96 - (__FUNCSIG__[sizeof(__FUNCSIG__) - 19] == ' ' ? 1 : 0)}; + return std::string_view{__FUNCSIG__ + 63, sizeof(__FUNCSIG__) - 81 - (__FUNCSIG__[sizeof(__FUNCSIG__) - 19] == ' ' ? 1 : 0)}; #else - static_assert(always_false{}, "nameof::nameof_type: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); return std::string_view{}; // Unsupported compiler. #endif } } // namespace nameof::detail +inline constexpr auto is_nameof_type_supported = detail::nameof_type_supported::value; + +inline constexpr auto is_nameof_enum_supported = detail::nameof_enum_supported::value; + // Obtains simple (unqualified) string enum name of enum variable. template [[nodiscard]] constexpr detail::enable_if_enum_t nameof_enum(E value) noexcept { using D = detail::remove_cvref_t; + static_assert(detail::nameof_enum_supported::value, "nameof::nameof_enum: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); static_assert(std::is_enum_v, "nameof::nameof_enum requires enum type."); static_assert(enum_range::min > (std::numeric_limits::min)(), "nameof::enum_range requires min must be greater than INT_MIN."); static_assert(enum_range::max < (std::numeric_limits::max)(), "nameof::enum_range requires max must be less than INT_MAX."); @@ -227,7 +243,7 @@ template using U = std::underlying_type_t; constexpr auto max = enum_range::max < (std::numeric_limits::max)() ? enum_range::max : (std::numeric_limits::max)(); constexpr auto min = enum_range::min > (std::numeric_limits::min)() ? enum_range::min : (std::numeric_limits::min)(); - constexpr auto names = detail::enum_names_impl(std::make_integer_sequence{}); + constexpr auto names = detail::enum_names(std::make_integer_sequence{}); if (auto i = static_cast(static_cast(value) - min); i < names.size()) { return names[i]; @@ -241,37 +257,40 @@ template template [[nodiscard]] constexpr detail::enable_if_enum_t nameof_enum() noexcept { using D = detail::remove_cvref_t; + static_assert(detail::nameof_enum_supported::value, "nameof::nameof_enum: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); static_assert(std::is_enum_v, "nameof::nameof_enum requires enum type."); - return detail::nameof_enum_impl(); + return detail::n(); } // Obtains string name of full type, with reference and cv-qualifiers. template [[nodiscard]] constexpr std::string_view nameof_full_type() noexcept { + static_assert(detail::nameof_type_supported::value, "nameof::nameof_type: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); #if defined(_MSC_VER) - return detail::nameof_type_impl>(); + return detail::n>(); #else - return detail::nameof_type_impl(); + return detail::n(); #endif } // Obtains string name of type, reference and cv-qualifiers are ignored. template [[nodiscard]] constexpr std::string_view nameof_type() noexcept { + static_assert(detail::nameof_type_supported::value, "nameof::nameof_type: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); return nameof_full_type>(); } } // namespace nameof // Obtains simple (unqualified) string name of variable, function, enum, macro. -#define NAMEOF(...) ::nameof::detail::nameof_impl<::std::void_t>(#__VA_ARGS__, true) +#define NAMEOF(...) ::nameof::detail::nameof<::std::void_t>(#__VA_ARGS__, true) // Obtains simple (unqualified) full (with template suffix) string name of variable, function, enum, macro. -#define NAMEOF_FULL(...) ::nameof::detail::nameof_impl<::std::void_t>(#__VA_ARGS__, false) +#define NAMEOF_FULL(...) ::nameof::detail::nameof<::std::void_t>(#__VA_ARGS__, false) // Obtains raw string name of variable, function, enum, macro. -#define NAMEOF_RAW(...) ::nameof::detail::nameof_raw_impl<::std::void_t>(#__VA_ARGS__) +#define NAMEOF_RAW(...) ::nameof::detail::nameof_raw<::std::void_t>(#__VA_ARGS__) // Obtains simple (unqualified) string enum name of enum variable. #define NAMEOF_ENUM(...) ::nameof::nameof_enum(__VA_ARGS__)