Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was never required and should be removed; internal documentation remains in the comments.


## Enum Range

* For non-flag enums, range-based reflection only considers values in `[MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]`.
Expand Down
22 changes: 22 additions & 0 deletions doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,28 @@ constexpr auto enum_for_each(Lambda&& lambda);
});
```

## `bind_front`

```cpp
template <typename F, typename... Args>
constexpr auto bind_front(F&& f, Args&&... args);
```

* Defined in header `<magic_enum/magic_enum_utility.hpp>`

* 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
Expand Down
27 changes: 27 additions & 0 deletions include/magic_enum/magic_enum_utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

#ifndef MAGIC_ENUM_USE_STD_MODULE
# include <tuple>
# include <utility>
#endif

namespace magic_enum {
Expand Down Expand Up @@ -144,6 +145,32 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
return MAGIC_ENUM_ASSERT(false), value;
}

template <typename F, typename... BoundArgs>
class bind_front_t {
public:
template <typename Fn, typename... Args>
constexpr explicit bind_front_t(Fn&& fn, Args&&... args)
: fn_(std::forward<Fn>(fn)), bound_(std::forward<Args>(args)...) {}

template <typename... CallArgs>
constexpr decltype(auto) operator()(CallArgs&&... call_args) const {
return std::apply(
fn_,
std::tuple_cat(bound_,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid tuple_cat here: it copies bound arguments into a temporary and breaks mutable callables, lvalue references, move-only values, and reference returns. Invoke the stored arguments directly via std::get, preserving the wrapper value category with &, const&, &&, and const&& overloads.

std::forward_as_tuple(std::forward<CallArgs>(call_args)...)));
}

private:
F fn_;
std::tuple<BoundArgs...> bound_;
};

template <typename F, typename... Args>
[[nodiscard]] constexpr auto bind_front(F&& f, Args&&... args) {
return bind_front_t<std::decay_t<F>, std::decay_t<Args>...>{
std::forward<F>(f), std::forward<Args>(args)...};
}

} // namespace magic_enum

#endif // NEARGYE_MAGIC_ENUM_UTILITY_HPP
13 changes: 13 additions & 0 deletions test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,19 @@ TEST_CASE("enum_for_each") {
}
}

TEST_CASE("bind_front") {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test does not verify fix for issue #200.

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
Expand Down
Loading