DMarlon Studio

Lesson 16 · 16 of 20

Namespaces and enum class · C++

Organise C++ code with namespaces, aliases and using, and use enum class for safe named states: the steps of an online order.

C++ · Namespaces and enum class in DMarlon Studio: the example's code and its output in the terminal

A namespace groups names so they do not clash with names from other parts of the program or other libraries: shop::label cannot be confused with any other label. That is what std:: does for the whole standard library. From outside, you use the full name with ::.

Since C++17, namespace shop::tax opens a nested namespace in a single line, and namespace tx = shop::tax; creates a shorter alias. using shop::OrderStatus; brings just that one name into main's block, which is safer than pulling in a whole namespace with using namespace.

`enum class` defines a type with named values. Unlike the classic enum, its names live inside the type (OrderStatus::Paid) and do not turn into integers on their own: status == 2 would not compile. Moving to the next step needs a deliberate conversion, static_cast<int> and back with static_cast<OrderStatus>; values start at 0, so "shipped" is step 2.

You can also choose the underlying type: Priority : char stores each value as a character, 'L' or 'H'. The switch in label covers every status; add a new one and forget it here, and -Wall will warn you. constexpr double vat is a constant the compiler knows in advance, as you will see in lesson 19.

Code · main.cpp

#include <iostream>#include <string>namespace shop {    // enum class: scoped names that do not turn into int on their own.    enum class OrderStatus { Pending, Paid, Shipped, Delivered };    enum class Priority : char { Low = 'L', High = 'H' };    // chosen underlying type    std::string label(OrderStatus s) {        switch (s) {            case OrderStatus::Pending:   return "pending";            case OrderStatus::Paid:      return "paid";            case OrderStatus::Shipped:   return "shipped";            case OrderStatus::Delivered: return "delivered";        }        return "unknown";    }}namespace shop::tax {                  // a nested namespace (C++17 syntax)    constexpr double vat = 0.21;    double withVat(double net) { return net * (1 + vat); }}namespace tx = shop::tax;              // a shorter aliasint main() {    using shop::OrderStatus;           // bring in just this one name    OrderStatus status = OrderStatus::Paid;    std::cout << "Order is " << shop::label(status) << "\n";    status = static_cast<OrderStatus>(static_cast<int>(status) + 1);    // next step    std::cout << "Now it is " << shop::label(status) << " (step " << static_cast<int>(status) << ")\n";    std::cout << "Priority code: " << static_cast<char>(shop::Priority::High) << "\n";    std::cout << "120 EUR + VAT = " << tx::withVat(120) << " EUR\n";}

Output · c++ -std=c++17 main.cpp -o main && ./main

Order is paid
Now it is shipped (step 2)
Priority code: H
120 EUR + VAT = 145.2 EUR

Key points

  • namespace name { ... } groups code; use it as name::thing.
  • namespace a::b nests and namespace x = a::b; makes an alias.
  • using a::thing; brings in one name; avoid using namespace in headers.
  • enum class does not mix with integers without a static_cast.
  • enum class E : char chooses the type used for storage.

Exercise

Add a Cancelled status to OrderStatus, compile to see the switch warning, and complete label so it returns "cancelled".