Skip to content

Commit

Permalink
std::visit
Browse files Browse the repository at this point in the history
  • Loading branch information
alexkaratarakis committed Sep 14, 2024
1 parent 5954886 commit 9310333
Showing 1 changed file with 123 additions and 15 deletions.
138 changes: 123 additions & 15 deletions test/enum_utils_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,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;

Check failure on line 175 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

defaulted member ‘constexpr bool fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::operator==(const fixed_containers::rich_enums::nested_enums::ColorVariant<>&) const’ must have parameter type ‘const fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>&’

Check failure on line 175 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / Analyze (cpp, gcc-11, Ninja, Debug, OFF)

defaulted member ‘constexpr bool fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::operator==(const fixed_containers::rich_enums::nested_enums::ColorVariant<>&) const’ must have parameter type ‘const fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>&’

Check failure on line 175 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

defaulted member ‘constexpr bool fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::operator==(const fixed_containers::rich_enums::nested_enums::ColorVariant<>&) const’ must have parameter type ‘const fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>&’
constexpr auto operator<=>(const ColorVariant<>& other) const = default;

Check failure on line 176 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

defaulted member ‘constexpr auto fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::operator<=>(const fixed_containers::rich_enums::nested_enums::ColorVariant<>&) const’ must have parameter type ‘const fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>&’

Check failure on line 176 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / Analyze (cpp, gcc-11, Ninja, Debug, OFF)

defaulted member ‘constexpr auto fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::operator<=>(const fixed_containers::rich_enums::nested_enums::ColorVariant<>&) const’ must have parameter type ‘const fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>&’

Check failure on line 176 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

defaulted member ‘constexpr auto fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::operator<=>(const fixed_containers::rich_enums::nested_enums::ColorVariant<>&) const’ must have parameter type ‘const fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>&’

const ColorStdVariant& as_std_variant() const { return variant_; }
ColorStdVariant& as_std_variant() { return variant_; }
};

enum class ColorBackingEnum
Expand Down Expand Up @@ -200,6 +216,12 @@ struct ColorValues
}();

Check failure on line 216 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

‘constexpr’ call flows off the end of the function

Check failure on line 216 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / Analyze (cpp, gcc-11, Ninja, Debug, OFF)

‘constexpr’ call flows off the end of the function

Check failure on line 216 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

‘constexpr’ call flows off the end of the function
};

template <class... Ts>
struct overloaded : Ts...
{
using Ts::operator()...;
};

class Color : public SkeletalRichEnum<Color, ColorBackingEnum>
{
private:
Expand Down Expand Up @@ -240,6 +262,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 @@ -273,10 +301,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());

Check failure on line 305 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

call to non-‘constexpr’ function ‘const ColorStdVariant& fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::as_std_variant() const [with auto COLOR = fixed_containers::rich_enums::nested_enums::ColorVariantAll::INVALID; fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::ColorStdVariant = std::variant<fixed_containers::rich_enums::nested_enums::ColorVariantRed, fixed_containers::rich_enums::nested_enums::ColorVariantBlue>]’

Check failure on line 305 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / Analyze (cpp, gcc-11, Ninja, Debug, OFF)

call to non-‘constexpr’ function ‘const ColorStdVariant& fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::as_std_variant() const [with auto COLOR = fixed_containers::rich_enums::nested_enums::ColorVariantAll::INVALID; fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::ColorStdVariant = std::variant<fixed_containers::rich_enums::nested_enums::ColorVariantRed, fixed_containers::rich_enums::nested_enums::ColorVariantBlue>]’

Check failure on line 305 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

call to non-‘constexpr’ function ‘const ColorStdVariant& fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::as_std_variant() const [with auto COLOR = fixed_containers::rich_enums::nested_enums::ColorVariantAll::INVALID; fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::ColorStdVariant = std::variant<fixed_containers::rich_enums::nested_enums::ColorVariantRed, fixed_containers::rich_enums::nested_enums::ColorVariantBlue>]’
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 @@ -303,10 +332,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());

Check failure on line 336 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

call to non-‘constexpr’ function ‘const ColorStdVariant& fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::as_std_variant() const [with auto COLOR = fixed_containers::rich_enums::nested_enums::ColorVariantAll::INVALID; fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::ColorStdVariant = std::variant<fixed_containers::rich_enums::nested_enums::ColorVariantRed, fixed_containers::rich_enums::nested_enums::ColorVariantBlue>]’

Check failure on line 336 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / Analyze (cpp, gcc-11, Ninja, Debug, OFF)

call to non-‘constexpr’ function ‘const ColorStdVariant& fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::as_std_variant() const [with auto COLOR = fixed_containers::rich_enums::nested_enums::ColorVariantAll::INVALID; fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::ColorStdVariant = std::variant<fixed_containers::rich_enums::nested_enums::ColorVariantRed, fixed_containers::rich_enums::nested_enums::ColorVariantBlue>]’

Check failure on line 336 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

call to non-‘constexpr’ function ‘const ColorStdVariant& fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::as_std_variant() const [with auto COLOR = fixed_containers::rich_enums::nested_enums::ColorVariantAll::INVALID; fixed_containers::rich_enums::nested_enums::ColorVariant<COLOR>::ColorStdVariant = std::variant<fixed_containers::rich_enums::nested_enums::ColorVariantRed, fixed_containers::rich_enums::nested_enums::ColorVariantBlue>]’
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 @@ -319,35 +349,110 @@ class ColorVariant<ColorBase::BLUE()>
}
};

static void do_stuff_with_plain_color(const Color& color)
static 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;
}
}

static 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;
}
});
}

static 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(false);

Check failure on line 435 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

static assertion failed

Check failure on line 435 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / Analyze (cpp, gcc-11, Ninja, Debug, OFF)

static assertion failed

Check failure on line 435 in test/enum_utils_test.cpp

View workflow job for this annotation

GitHub Actions / build

static assertion failed
}
},
color.color_variant().as_std_variant());
}

static 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 @@ -357,10 +462,10 @@ static 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 @@ -371,7 +476,10 @@ static void do_stuff_with_plain_color(const Color& color)
TEST(NestedEnums, Example)
{
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 9310333

Please sign in to comment.