magic_enum icon indicating copy to clipboard operation
magic_enum copied to clipboard

Support no default value enum_switch

Open Sarna555 opened this issue 3 years ago • 11 comments

would it be possible to support enum_switch the way that we're used to use overload pattern with std::visit? e.g

return magic_enum::enum_switch( overloaded{
           []( my_enum::val1 arg ) -> int { /* handle val1 enum */ return 1; },
           []( auto arg ) -> int { /* handle the rest */ throw notimplemented; /* or just return sth */ }
});

instead of

return magic_enum::enum_switch( overloaded{
           []( my_enum::val1 arg ) -> int { /* handle val1 enum */ return 1; },
           []( auto arg ) -> int { /* handle the rest */ throw notimplemented; /* or just return sth */ }
}, /*redundant default*/ int(2));

// or probably worse

auto r = magic_enum::enum_switch(
           []( my_enum::val1 arg ) -> int { /* handle val1 enum */ return 1; }
           , int(2)
);

if( r == 2 ) throw notimplemented;

I think forcing adding default Result produces boilerplate.

Sarna555 avatar Jul 11 '22 13:07 Sarna555

If you need to iterate over all values ​​then use enum_for_each

enum_switch does not take a default value, it takes a value that will be handled in the switch

Neargye avatar Jul 11 '22 15:07 Neargye

Yes, sorry I made a mistake in the example above.

return magic_enum::enum_switch( overloaded{
           []( my_enum::val1 arg ) -> int { /* handle val1 enum */ return 1; },
           []( auto arg ) -> int { /* handle the rest */ throw notimplemented; /* or just return sth */ }
}, enumValue);

I'm taking about return value of enum_switch from docs

template <typename Result = void, typename E, typename Lambda>
constexpr Result enum_switch(Lambda&& lambda, E value);

template <typename Result, typename E, typename Lambda>
constexpr Result enum_switch(Lambda&& lambda, E value, Result&& result);

If I want to return a value from enum_switch (Result is not void) I need to pass additional argument and It'd be nice not being forced to do so.

Sarna555 avatar Jul 12 '22 07:07 Sarna555

return magic_enum::enum_switch<int>( overloaded{
           []( my_enum::val1 arg ) -> int { /* handle val1 enum */ return 1; },
           []( auto arg ) -> int { /* handle the rest */ throw notimplemented; /* or just return sth */ }
}, enumValue);

see https://github.com/Neargye/magic_enum/blob/master/example/example_switch.cpp

Neargye avatar Jul 12 '22 09:07 Neargye

ok, but I still need to specify the return type explicitly. In case of std::visit as long as all the lambdas in overload return the same value there is no need for additional code.

std::visit( overloaded { []( const Type1 val ) { return int(1); }, 
                         []( const Type2 val ) { return float(2); }
           }); // compilation error

std::visit( overloaded { []( const Type1 val ) { return int(1); }, 
                         []( const Type2 val ) -> int { return float(2); }
           }); // fine

std::visit( overloaded { []( const Type1 val ) { return int(1); }, 
                         []( const Type2 val ) { return int(2); }
           }); // fine

Sarna555 avatar Jul 12 '22 10:07 Sarna555

I'll see what i can do

Neargye avatar Jul 12 '22 12:07 Neargye

The switch is not required to handle all cases (especially unrecognized values), so when explicitly isn't set the result (or the type) for the magic_enum::enum_switch call, the result type cannot be guessed for all case return value.


What will be the result for example 4 different result type without explicitly set the result? std::common_type<R1, R2 ...>? And if it isn't constructible, or a base class? What will be the result of any unrecognized (unnamed) enum value? How can be handle this? This will cause error message, when the result type is not default constructible.

What if someone didn't handle all case, and lambda can't be instantiated with some value?

Many unanswered question will come up if we enable enum_switch result type deduction from only the callback.


So the current rule is: If you explicit set the type, you are the responsible to this type can be default construct. If you want to use result type that cannot be default construct, you have to pass the default result object. Else, the switch return void.

and there are no "better" way to do otherwise.

schaumb avatar Jul 21 '22 21:07 schaumb

@schaumb I like the option to make it consistent with the std::visit, so that there is a fallback for all possible enums or defaults. This is also consistent with the enum warnings switch that you need to case all values ​​or the default case.

If you don't mind, I can add the necessary traits for the checks inside the function.

Neargye avatar Aug 08 '22 21:08 Neargye

If I wrote a swich, I don't need to write all case / default.

I think this is an another use-case, and probably not a switch but a visit. I think this can be a different function which uses enum_switch with type-traits check, to handle all case + default, and guess the result type.

enum_visit ?

schaumb avatar Aug 09 '22 13:08 schaumb

@Sarna555 https://github.com/Neargye/magic_enum/pull/212 I tried to improve the deduction of the return type of the enum_switch, but the function signature changed a little

enum_switch will try to deduce return the type, if this is not possible, then you still need have to specify the return type explicitly

Neargye avatar Sep 02 '22 21:09 Neargye

@Sarna555 #212 I tried to improve the deduction of the return type of the enum_switch, but the function signature changed a little

enum_switch will try to deduce return the type, if this is not possible, then you still need have to specify the return type explicitly

Yes, this is what I meant, not having to specify the return type. Is it something that could be merged to the master branch and released?

Sarna555 avatar Sep 07 '22 11:09 Sarna555

@Sarna555 #212 I tried to improve the deduction of the return type of the enum_switch, but the function signature changed a little enum_switch will try to deduce return the type, if this is not possible, then you still need have to specify the return type explicitly

Yes, this is what I meant, not having to specify the return type. Is it something that could be merged to the master branch and released?

I'll take it to the master and release after some additional testing.

Neargye avatar Sep 07 '22 13:09 Neargye

Fix in master Will be include in next release

Neargye avatar Nov 07 '22 17:11 Neargye