https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109249
--- Comment #2 from Andre Schackier <andre.schackier at gmail dot com> --- I'm soryy will keep that in mind for the future :) Example #1: #include <array> #include <cstdint> enum class Type { None, Bug, Dark, Dragon, Electric, Fighting, Fire, Flying, Ghost, Grass, Ground, Ice, Normal, Poison, Psychic, Rock, Steel, Water, Count, }; static constexpr const std::size_t NumberOfTypes = static_cast<std::size_t>(Type::Count); namespace detail { constexpr float GetTypeDamageMultiplierImpl(Type defending_type, Type attacking_type) noexcept { switch (defending_type) { case Type::None: return 1.0f; case Type::Bug: switch (attacking_type) { case Type::Fighting: case Type::Grass: case Type::Ground: return 0.5f; case Type::Fire: case Type::Flying: case Type::Rock: return 2.0f; default: return 1.0f; } case Type::Dark: switch (attacking_type) { case Type::Psychic: return 0.0f; case Type::Dark: case Type::Ghost: return 0.5f; case Type::Bug: case Type::Fighting: return 2.0f; default: return 1.0f; } case Type::Dragon: switch (attacking_type) { case Type::Electric: case Type::Fire: case Type::Grass: case Type::Water: return 0.5f; case Type::Dragon: case Type::Ice: return 2.0f; default: return 1.0f; } case Type::Electric: switch (attacking_type) { case Type::Electric: case Type::Flying: case Type::Steel: return 0.5f; case Type::Ground: return 2.0f; default: return 1.0f; } case Type::Fighting: switch (attacking_type) { case Type::Bug: case Type::Dark: case Type::Rock: return 0.5f; case Type::Flying: case Type::Psychic: return 2.0f; default: return 1.0f; } case Type::Fire: switch (attacking_type) { case Type::Bug: case Type::Fire: case Type::Grass: case Type::Ice: case Type::Steel: return 0.5f; case Type::Ground: case Type::Rock: case Type::Water: return 2.0f; default: return 1.0f; } case Type::Flying: switch (attacking_type) { case Type::Ground: return 0.0f; case Type::Bug: case Type::Fighting: case Type::Grass: return 0.5f; case Type::Electric: case Type::Ice: case Type::Rock: return 2.0f; default: return 1.0f; } case Type::Ghost: switch (attacking_type) { case Type::Normal: case Type::Fighting: return 0.0f; case Type::Bug: case Type::Poison: return 0.5f; case Type::Dark: case Type::Ghost: return 2.0f; default: return 1.0f; } case Type::Grass: switch (attacking_type) { case Type::Electric: case Type::Grass: case Type::Ground: case Type::Water: return 0.5f; case Type::Bug: case Type::Fire: case Type::Flying: case Type::Ice: case Type::Poison: return 2.0f; default: return 1.0f; } case Type::Ground: switch (attacking_type) { case Type::Electric: return 0.0f; case Type::Poison: case Type::Rock: return 0.5f; case Type::Grass: case Type::Ice: case Type::Water: return 2.0f; default: return 1.0f; } case Type::Ice: switch (attacking_type) { case Type::Ice: return 0.5f; case Type::Fighting: case Type::Fire: case Type::Rock: case Type::Steel: return 2.0f; default: return 1.0f; } case Type::Normal: switch (attacking_type) { case Type::Ghost: return 0.0f; case Type::Fighting: return 2.0f; default: return 1.0f; } case Type::Poison: switch (attacking_type) { case Type::Fighting: case Type::Poison: case Type::Bug: case Type::Grass: return 0.5f; case Type::Ground: case Type::Psychic: return 2.0f; default: return 1.0f; } case Type::Psychic: switch (attacking_type) { case Type::Fighting: case Type::Psychic: return 0.5f; case Type::Bug: case Type::Dark: case Type::Ghost: return 2.0f; default: return 1.0f; } case Type::Rock: switch (attacking_type) { case Type::Fire: case Type::Flying: case Type::Normal: case Type::Poison: return 0.5f; case Type::Fighting: case Type::Grass: case Type::Ground: case Type::Steel: case Type::Water: return 2.0f; default: return 1.0f; } case Type::Steel: switch (attacking_type) { case Type::Poison: return 0.0f; case Type::Bug: case Type::Dark: case Type::Dragon: case Type::Flying: case Type::Ghost: case Type::Grass: case Type::Ice: case Type::Normal: case Type::Psychic: case Type::Rock: case Type::Steel: return 0.5f; case Type::Fighting: case Type::Fire: case Type::Ground: return 2.0f; default: return 1.0f; } case Type::Water: switch (attacking_type) { case Type::Fire: case Type::Ice: case Type::Steel: case Type::Water: return 0.5f; case Type::Electric: case Type::Grass: return 2.0f; default: return 1.0f; } default: __builtin_unreachable(); } } constexpr std::array<float, NumberOfTypes * NumberOfTypes> GenerateTypeDamageTable() noexcept { std::array<float, NumberOfTypes * NumberOfTypes> table{}; for (std::uint32_t defending_type{0u}; defending_type < NumberOfTypes; ++defending_type) { for (std::uint32_t attacking_type{0u}; attacking_type < NumberOfTypes; ++attacking_type) { table[defending_type * NumberOfTypes + attacking_type] = GetTypeDamageMultiplierImpl(static_cast<Type>(defending_type), static_cast<Type>(attacking_type)); } } return std::move(table); } } // namespace detail float GetTypeDamageMultiplier(Type defending_type, Type attacking_type) noexcept { constexpr const auto table = detail::GenerateTypeDamageTable(); return table[static_cast<std::size_t>(defending_type) * NumberOfTypes + static_cast<std::size_t>(attacking_type)]; } Example #2: #include <array> #include <cstdint> enum class Type { None, Bug, Dark, Dragon, Electric, Fighting, Fire, Flying, Count, }; static constexpr const std::size_t NumberOfTypes = static_cast<std::size_t>(Type::Count); namespace detail { constexpr float GetTypeDamageMultiplierImpl( const Type defending_type, const Type attacking_type) noexcept { switch (defending_type) { case Type::None: return 1.0f; case Type::Bug: switch (attacking_type) { case Type::Fighting: return 0.5f; case Type::Fire: case Type::Flying: return 2.0f; default: return 1.0f; } case Type::Dark: switch (attacking_type) { case Type::Dark: return 0.5f; case Type::Bug: case Type::Fighting: return 2.0f; default: return 1.0f; } case Type::Dragon: switch (attacking_type) { case Type::Electric: case Type::Fire: return 0.5f; case Type::Dragon: return 2.0f; default: return 1.0f; } case Type::Electric: switch (attacking_type) { case Type::Electric: case Type::Flying: return 0.5f; default: return 1.0f; } case Type::Fighting: switch (attacking_type) { case Type::Bug: case Type::Dark: return 0.5f; case Type::Flying: return 2.0f; default: return 1.0f; } case Type::Fire: switch (attacking_type) { case Type::Bug: case Type::Fire: return 0.5f; default: return 1.0f; } case Type::Flying: switch (attacking_type) { case Type::Bug: case Type::Fighting: return 0.5f; case Type::Electric: return 2.0f; default: return 1.0f; } default: __builtin_unreachable(); } } constexpr std::array<float, NumberOfTypes * NumberOfTypes> GenerateTypeDamageTable() noexcept { std::array<float, NumberOfTypes * NumberOfTypes> table{}; for (std::uint32_t defending_type{0u}; defending_type < NumberOfTypes; ++defending_type) { for (std::uint32_t attacking_type{0u}; attacking_type < NumberOfTypes; ++attacking_type) { table[defending_type * NumberOfTypes + attacking_type] = GetTypeDamageMultiplierImpl(static_cast<Type>(defending_type), static_cast<Type>(attacking_type)); } } return std::move(table); } } // namespace detail float GetTypeDamageMultiplier(const Type defending_type, const Type attacking_type) noexcept { constexpr const auto table = detail::GenerateTypeDamageTable(); return table[static_cast<std::size_t>(defending_type) * NumberOfTypes + static_cast<std::size_t>(attacking_type)]; }