enum class instead of unscoped enum – EasyHack
Since C++11 when enum class
(also named scoped enum
) is introduced, it is preferred to plain enum
which is inherited from C programming languages. The task here is to convert the old enum
instances to enum class
.
Rationale
enum class
has many benefits when compared to plain enum
, as it provides better type safety among other things. Implicit conversion to integers, lack of ability to define the underlying data type and compatibility issues were some of the problems with plain enum
that enum class
solved in C++11. Although since then enum
has improved and one can specify underlying type in the scoped enumerations.
Plain enums
pollute namespace, and you have to pick names that are too long, and have to carry the context inside their names. For example: INETMSG_RFC822_BEGIN
inside enum _ImplINetRFC822MessageHeaderState
. With an enum class
, it is simply written as HeaderState::BEGIN
. When placed inside a file/class/namespace that makes it relevant, it is much easier to use: it is more readable, and causes no issues for other identifiers with possible similar names.,
See this change:
You can read more about that in:
Finding Instances
You may find some of the instances with:
$ git grep -w enum *.cxx *.hxx|grep -v "enum class"
When you count it with wc -l
, it shows something more than 2k instances.
Examples Commits
You can see some of the previous conversions here, which is around 1k changes:
$ git log --oneline -i -E --grep="convert enum|scoped enum"
This is a good, but lengthy example of such a conversion:
Implementation
First of all, please choose good names for the new enum class
and values. For example, you may convert APPLICATION_WINDOW_TITLE
into Application::WindowTitle
. Therefore, do not use the old names as they were.
Converting enum
to enum class
is not always straightforward. You should try to understand the code using the enum
, and then try to replace it with enum class
. You may need to add extra state/values for situations where 0 or -1 or some default value was used. There are cases where a numerical value is used for different conflicting purposes, and then you have to do some sort of conflict resolution to separate those cases.
You may end up modifying more and more files, and a few static_casts
where they are absolutely necessary because you are interpreting some integer value read from input. These are the places where you should check the values yourself in the code. You have to make sure that the numerical value is appropriate before casting it to the enum class
.
If you want to do bitwise operations, you should use o3tl::typed_flags
, for example:
enum class FileViewFlags { None = 0x00, MultiSelection = 0x02, ShowType = 0x04, ShowNone = 0x20, }; template<> struct o3tl::typed_flags : o3tl::is_typed_flags<FileViewFlags, 0x26> {}
Then, you may use it like this:
if (nFlags & FileViewFlags::MULTISELECTION) mxTreeView->set_selection_mode(SelectionMode::Multiple);
Please note that 0x26
is the mask, and is calculated by applying OR
over all possible values. All the values must be non-negative.
Final Notes
This is a simple development task for LibreOffice also known as EasyHack, which is filed in Bugzilla as tdf#168771. These small tasks are defined to help newcomers to LibreOffice development community to improve their skills with LibreOffice coding.
You may find other instances related to C++ here: