Skip to content

Commit

Permalink
std::visit
Browse files Browse the repository at this point in the history
  • Loading branch information
alexkaratarakis committed Sep 15, 2024
1 parent fc58f2f commit 68ffd5f
Showing 1 changed file with 117 additions and 15 deletions.
132 changes: 117 additions & 15 deletions test/enum_utils_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,26 @@ enum class ColorVariantAll
};

template <auto COLOR = ColorVariantAll{}>
class ColorVariant : public std::variant<ColorVariantRed, ColorVariantBlue>
class ColorVariant
{
public:
using variant::variant;
using ColorStdVariant = std::variant<ColorVariantRed, ColorVariantBlue>;

private:
ColorStdVariant variant_{};

public:
template <typename... Args>
constexpr ColorVariant(Args&&... args)
: variant_{std::forward<Args>(args)...}
{
}

constexpr bool operator==(const ColorVariant<>& other) const = default;
constexpr auto operator<=>(const ColorVariant<>& other) const = default;

[[nodiscard]] const ColorStdVariant& as_std_variant() const { return variant_; }
ColorStdVariant& as_std_variant() { return variant_; }
};

enum class ColorBackingEnum
Expand Down Expand Up @@ -243,6 +259,12 @@ class Color : public SkeletalRichEnum<Color, ColorBackingEnum>
{
return ColorValues::VALUES.at(backing_enum()).color_variant;
}

template <typename... Args>
constexpr void variant_switch(Args&&... args) const
{
std::visit(Overloaded{std::forward<Args>(args)...}, color_variant().as_std_variant());
}
};

static constexpr EnumSet<Color> ALL_RED_VARIANTS = []()
Expand Down Expand Up @@ -276,10 +298,11 @@ class ColorVariant<ColorBase::RED()>
static constexpr OptionalReference<const ColorVariant<ColorBase::RED()>> from(
const ColorVariant<>& flat_variant)
{
if (const ColorVariantRed* valid_variant = std::get_if<ColorVariantRed>(&flat_variant);
if (const ColorVariantRed* valid_variant =
std::get_if<ColorVariantRed>(&flat_variant.as_std_variant());
valid_variant != nullptr)
{
switch (std::get<ColorVariantRed>(flat_variant))
switch (std::get<ColorVariantRed>(flat_variant.as_std_variant()))
{
case ColorVariantRed::PINK:
return OptionalReference{PINK()};
Expand All @@ -306,10 +329,11 @@ class ColorVariant<ColorBase::BLUE()>
static constexpr OptionalReference<const ColorVariant<ColorBase::BLUE()>> from(
const ColorVariant<>& flat_variant)
{
if (const ColorVariantBlue* valid_variant = std::get_if<ColorVariantBlue>(&flat_variant);
if (const ColorVariantBlue* valid_variant =
std::get_if<ColorVariantBlue>(&flat_variant.as_std_variant());
valid_variant != nullptr)
{
switch (std::get<ColorVariantBlue>(flat_variant))
switch (std::get<ColorVariantBlue>(flat_variant.as_std_variant()))
{
case ColorVariantBlue::CYAN:
return OptionalReference{CYAN()};
Expand All @@ -324,35 +348,110 @@ class ColorVariant<ColorBase::BLUE()>

namespace
{
void do_stuff_with_plain_color(const Color& color)
void flat_switch(const Color& color)
{
switch (color)
{
case Color::RED_PINK():
std::cout << "RED:PINK" << std::endl;
std::cout << "RED_PINK" << std::endl;
break;
case Color::RED_ORANGE():
std::cout << color.to_string() << std::endl;
break;
case Color::BLUE_CYAN():
std::cout << "BLUE:CYAN" << std::endl;
std::cout << "BLUE_CYAN" << std::endl;
break;
case Color::BLUE_AZURE():
std::cout << "BLUE:AZURE" << std::endl;
std::cout << "BLUE_AZURE" << std::endl;
break;
}
}

void automatic_hierarchical_switch(const Color& color)
{
color.variant_switch(
[](const ColorVariantRed& variant)
{
switch (variant)
{
case ColorVariantRed::PINK:
std::cout << "RED:PINK2" << std::endl;
break;
case ColorVariantRed::ORANGE:
std::cout << "RED:ORANGE2" << std::endl;
break;
}
},
[](const ColorVariantBlue& variant)
{
switch (variant)
{
case ColorVariantBlue::CYAN:
std::cout << "BLUE:CYAN2" << std::endl;
break;
case ColorVariant<ColorBase::BLUE()>::AZURE():
std::cout << "BLUE:AZURE2" << std::endl;
break;
}
});
}

void std_visit_with_if_constexpr(const Color& color)
{
std::visit(
[]<typename T>(const T& variant)
{
if constexpr (std::same_as<T, ColorVariantRed>)
{
switch (variant)
{
case ColorVariantRed::PINK:
std::cout << "RED:PINK3" << std::endl;
break;
case ColorVariantRed::ORANGE:
std::cout << "RED:ORANGE3" << std::endl;
break;
}
}
else if constexpr (std::same_as<T, ColorVariantBlue>)
{
switch (variant)
{
case ColorVariantBlue::CYAN:
std::cout << "BLUE:CYAN3" << std::endl;
break;
case ColorVariant<ColorBase::BLUE()>::AZURE():
std::cout << "BLUE:AZURE3" << std::endl;
break;
}
}
else
{
// if-constexpr has better compilation errors that std::visit but you have to
// remember to have this `static_assert`. `overloaded<...>` pattern has bad
// compilation errors, but you can't forget to handle a case. Syntax is also
// slightly convoluted.
static_assert(AlwaysFalseV<T>);
}
},
color.color_variant().as_std_variant());
}

void manual_hierarchical_switch(const Color& color)
{
switch (color.plain_color())
{
case ColorBase::RED():
{
// It is possible to have the wrong color here since the user is responsible for the nested
// switch
switch (ColorVariant<ColorBase::RED()>::from(color.color_variant()).value())
{
case ColorVariant<ColorBase::RED()>::PINK():
std::cout << "RED:PINK" << std::endl;
std::cout << "RED:PINK1" << std::endl;
break;
case ColorVariant<ColorBase::RED()>::ORANGE():
std::cout << "RED:ORANGE" << std::endl;
std::cout << "RED:ORANGE1" << std::endl;
break;
}
break;
Expand All @@ -362,10 +461,10 @@ void do_stuff_with_plain_color(const Color& color)
switch (ColorVariant<ColorBase::BLUE()>::from(color.color_variant()).value())
{
case ColorVariant<ColorBase::BLUE()>::CYAN():
std::cout << "BLUE:CYAN" << std::endl;
std::cout << "BLUE:CYAN1" << std::endl;
break;
case ColorVariant<ColorBase::BLUE()>::AZURE():
std::cout << "BLUE:AZURE" << std::endl;
std::cout << "BLUE:AZURE1" << std::endl;
break;
}
break;
Expand All @@ -378,7 +477,10 @@ TEST(NestedEnums, Example)
{
const Color color =
Color::from(ColorBase::BLUE(), ColorVariant<ColorBase::BLUE()>::AZURE()).value();
do_stuff_with_plain_color(color);
flat_switch(color);
automatic_hierarchical_switch(color);
std_visit_with_if_constexpr(color);
manual_hierarchical_switch(color);
}

} // namespace nested_enums
Expand Down

0 comments on commit 68ffd5f

Please sign in to comment.