string_view
operator+
vs. StrCat()
absl::Status
std::bind
absl::optional
and std::unique_ptr
absl::StrFormat()
make_unique
and private
Constructors.bool
explicit
= delete
)switch
Statements Responsibly= delete
AbslHashValue
and Youcontains()
std::optional
parametersif
and switch
statements with initializersinline
Variablesstd::unique_ptr
Must Be MovedAbslStringify()
vector.at()
auto
for Variable DeclarationsOriginally posted as totw/86 on 2015-01-05
By Bradley White ([email protected])
“Show class, … and display character.” - Bear Bryant.
An enumeration, or simply an enum, is a type that can hold one of a specified set of integers. Some values of this set can be given names, and are called the enumerators.
This concept will be familiar to C++ programmers, but prior to C++11 enumerations had two significant shortcomings: the enumeration names were:
So, with C++98 …
enum CursorDirection { kLeft, kRight, kUp, kDown };
CursorDirection d = kLeft; // OK: enumerator in scope
int i = kRight; // OK: enumerator converts to int
but, …
// error: redeclarations of kLeft and kRight
enum PoliticalOrientation { kLeft, kCenter, kRight };
C++11 modified the behavior of unscoped enums in one way: the enumerators are now local to the enum, but continue to be exported into the enum’s scope for backwards compatibility.
So, with C++11 …
CursorDirection d = CursorDirection::kLeft; // OK in C++11
int i = CursorDirection::kRight; // OK: still converts to int
but the declaration of PoliticalOrientation
would still elicit errors.
The implicit conversion to integer has been observed to be a common source of bugs, while the namespace pollution caused by having the enumerators in the same scope as the enum causes problems in large, multi-library projects. To address both these concerns, C++11 introduced a new concept: the scoped enum.
In a scoped enum, introduced by the keywords enum class
, the enumerators are:
So, (note the additional class keyword) …
enum class CursorDirection { kLeft, kRight, kUp, kDown };
CursorDirection d = kLeft; // error: kLeft not in this scope
CursorDirection d2 = CursorDirection::kLeft; // OK
int i = CursorDirection::kRight; // error: no conversion
and, …
// OK: kLeft and kRight are local to each scoped enum
enum class PoliticalOrientation { kLeft, kCenter, kRight };
These simple changes eliminate the problems with plain enumerations, so enum class should be preferred in all new code.
Using a scoped enum does mean that you’ll have to explicitly cast to an integer
type should you still want such a conversion (e.g., when logging an enumeration
value, or when using bitwise operations on flag-like enumerators). Hashing with
std::hash
will continue to work though (e.g.,
std::unordered_map<CursorDirection, int>
).
C++11 also introduced the ability to specify the underlying type for both varieties of enumeration. Previously the underlying integer type of an enum was determined by examining the sign and magnitude of the enumerators, but now we can be explicit. For example, …
// Use "int" as the underlying type for CursorDirection
enum class CursorDirection : int { kLeft, kRight, kUp, kDown };
Because this enumerator range is small, and if we wished to avoid wasting space
when storing CursorDirection
values, we could specify char
instead.
// Use "char" as the underlying type for CursorDirection
enum class CursorDirection : char { kLeft, kRight, kUp, kDown };
The compiler will issue an error if an enumerator value exceeds the range of the underlying type.
Prefer using enum class
in new code. You’ll reduce namespace pollution, and
you may avoid bugs in implicit conversions.
enum class Parting { kSoLong, kFarewell, kAufWiedersehen, kAdieu };