Learn C++ by Example by Frances Buontempo
Author:Frances Buontempo [Buontempo, Frances]
Language: eng
Format: epub
Publisher: Manning Publications Co.
Published: 2024-02-22T23:00:00+00:00
5.2.3 Using std::variant to support cards or jokers
The simplest way to define a joker is as an empty struct.
Listing 5.26 A joker
struct Joker { };
That is all we need.
We know how to make a deck of 52 playing cards:
std::array<Card, 52> cards = create_deck();
How do we add two jokers? We canât add jokers to this deck because they are a different type. We could make a common base type and use pointers for dynamic polymorphism, but that seems over the top. A much simpler approach would be an array of one of two types: cards or jokers. The std::variant, introduced in C++17, makes this possible. It lives in the variant header and behaves like a union, but it is safer. Câs union type has a sequence of possible members.
Listing 5.27 A union
union CardOrJoker { Card card; Joker joker; };
The union is big enough to hold the largest type used. To access a Card from this union, you use the card member, and for a Joker, use the joker member, but you need to track which type is in use. In contrast, a variant knows which type it currently holds, so the variant is often described as a type-safe union.
We declare a variant by stating which types it can hold:
std::variant<Card, Joker>
The variant is a class template defined as a variadic template. We will look at these in more detail in the last chapter, but for now, notice the three dots in the definition:
template <class... Types> class variant;
The dots are called a parameter pack, allowing us to use zero or more template arguments. This allows us to define a variant with the two types we need. We used std::optional in chapter 3 to handle input, which only needed one type. Declaring an optional without assigning a value
std::optional<Card> card;
has no value. If we use this card in a Boolean context, it will evaluate to false, so we could make an optional work, but the code might be hard to follow. Weâd need to remember that if(!card) meant we had a joker. How do we use a variant, then?
A variant is initialized to the first of the alternative types, provided that type can be default constructed. If it canât, we get a compile error. Both of our types can be default constructed, so that wonât happen here. So using
std::variant<Card, Joker> card;
gives us a default constructed Card because thatâs the first type. We could also create a Joker instead:
std::variant<Card, Joker> joker{ Joker{} };
In fact, there are various ways to create a variant. We can avoid making a temporary Joker{} to construct the variant using the std::in_place_index function. For a Joker, we want index 1 and do not have any arguments for the jokerâs constructor, so weâll use std::in_place_index with value 1:
std::variant<Card, Joker> joker2(std::in_place_index<1>);
For a Card, we use the zero index and pass the value and suit to the Card constructor:
std::variant<Card, Joker> two_of_clubs(std::in_place_index<0>, FaceValue(2), Suit::Clubs);
For further details, see http://mng.bz/amzY.
We can determine whether we have a joker by checking the variantâs type:
bool is_joker = std::holds_alternative<Joker>(two_of_clubs);
There are various ways to retrieve the values.
Download
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.
C | C++ |
Tutorials | Visual C++ |
Hello! Python by Anthony Briggs(9867)
OCA Java SE 8 Programmer I Certification Guide by Mala Gupta(9757)
The Mikado Method by Ola Ellnestam Daniel Brolund(9747)
Algorithms of the Intelligent Web by Haralambos Marmanis;Dmitry Babenko(8258)
Sass and Compass in Action by Wynn Netherland Nathan Weizenbaum Chris Eppstein Brandon Mathis(7745)
Test-Driven iOS Development with Swift 4 by Dominik Hauser(7741)
Grails in Action by Glen Smith Peter Ledbrook(7667)
The Well-Grounded Java Developer by Benjamin J. Evans Martijn Verburg(7517)
Windows APT Warfare by Sheng-Hao Ma(6502)
Secrets of the JavaScript Ninja by John Resig Bear Bibeault(6378)
Layered Design for Ruby on Rails Applications by Vladimir Dementyev(6248)
Blueprints Visual Scripting for Unreal Engine 5 - Third Edition by Marcos Romero & Brenden Sewell(6117)
Kotlin in Action by Dmitry Jemerov(5019)
Hands-On Full-Stack Web Development with GraphQL and React by Sebastian Grebe(4297)
Functional Programming in JavaScript by Mantyla Dan(4018)
Solidity Programming Essentials by Ritesh Modi(3839)
WordPress Plugin Development Cookbook by Yannick Lefebvre(3614)
Unity 3D Game Development by Anthony Davis & Travis Baptiste & Russell Craig & Ryan Stunkel(3566)
The Ultimate iOS Interview Playbook by Avi Tsadok(3532)
