diff --git a/doc/limitations.md b/doc/limitations.md index f06a34993..00799d412 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -21,6 +21,8 @@ * Zero is not reflected for flag enums. +* GCC 16 with `-std=c++26` may miscompile string parsing that uses `find`/`remove_prefix` on flag names. `enum_flags_cast` uses an explicit token loop instead; see [#467](https://github.com/Neargye/magic_enum/issues/467). + ## Enum Range * For non-flag enums, range-based reflection only considers values in `[MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]`. diff --git a/doc/reference.md b/doc/reference.md index 31af7de8e..a734592f2 100644 --- a/doc/reference.md +++ b/doc/reference.md @@ -511,6 +511,28 @@ constexpr auto enum_for_each(Lambda&& lambda); }); ``` +## `bind_front` + +```cpp +template +constexpr auto bind_front(F&& f, Args&&... args); +``` + +* Defined in header `` + +* C++17-compatible partial application helper. Useful with `enum_switch` to avoid nested lambdas on MSVC ([#200](https://github.com/Neargye/magic_enum/issues/200)). + +* Example + + ```cpp + enum class Shape { Circle, Square }; + auto describe = [](Shape s, std::string_view prefix) { + return std::string(prefix) + magic_enum::enum_name(s).data(); + }; + auto describe_circle = magic_enum::bind_front(describe, Shape::Circle); + describe_circle("shape: "); // -> "shape: Circle" + ``` + ## `enum_next_value` and `enum_prev_value` ```cpp diff --git a/include/magic_enum/magic_enum_utility.hpp b/include/magic_enum/magic_enum_utility.hpp index bad9bba27..7f959c8cf 100644 --- a/include/magic_enum/magic_enum_utility.hpp +++ b/include/magic_enum/magic_enum_utility.hpp @@ -36,6 +36,7 @@ #ifndef MAGIC_ENUM_USE_STD_MODULE # include +# include #endif namespace magic_enum { @@ -144,6 +145,32 @@ template > return MAGIC_ENUM_ASSERT(false), value; } +template +class bind_front_t { + public: + template + constexpr explicit bind_front_t(Fn&& fn, Args&&... args) + : fn_(std::forward(fn)), bound_(std::forward(args)...) {} + + template + constexpr decltype(auto) operator()(CallArgs&&... call_args) const { + return std::apply( + fn_, + std::tuple_cat(bound_, + std::forward_as_tuple(std::forward(call_args)...))); + } + + private: + F fn_; + std::tuple bound_; +}; + +template +[[nodiscard]] constexpr auto bind_front(F&& f, Args&&... args) { + return bind_front_t, std::decay_t...>{ + std::forward(f), std::forward(args)...}; +} + } // namespace magic_enum #endif // NEARGYE_MAGIC_ENUM_UTILITY_HPP diff --git a/test/test.cpp b/test/test.cpp index 9f989ac3a..e1f1c5448 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1315,6 +1315,19 @@ TEST_CASE("enum_for_each") { } } +TEST_CASE("bind_front") { + auto add = [](int a, int b, int c) { return a + b + c; }; + auto add_ab = magic_enum::bind_front(add, 1, 2); + REQUIRE(add_ab(3) == 6); + + enum class Shape { Circle, Square }; + auto describe = [](Shape s, std::string_view prefix) { + return std::string(prefix) + magic_enum::enum_name(s).data(); + }; + auto describe_circle = magic_enum::bind_front(describe, Shape::Circle); + REQUIRE(describe_circle("shape: ") == "shape: Circle"); +} + #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920 # define MAGIC_ENUM_SUPPORTED_CONSTEXPR_FOR 1 #endif