In section ref(ERRORCODEEXC) the class tt(std::error_code) was introduced. One
of its constructors accepts an ti(ErrorCodeEnum). Enums we
define ourselves may be `promoted' to tt(ErrorCodeEnums), allowing their use
by tt(error_code) and comparable classes. 

Standard error code values (like the tt(errno) values), or the values defined
by tt(enum class Errc) are used by low-level system functions like
bf(stat)(2), but they may not be suited for errors encountered by your own
functions or classes. For example, when designing an interactive calculator,
several errors may be encountered that are related to the way expressions are
entered by the user. For those situations you might want to develop your own
tt(ErrorCodeEnum). At the same time, the organization of the classes involved
in using tt(system_error) exceptions is complex, and the situation is further
complicated when different developers use their own self-defined enumerations
and classes. For example, it is enticing to list error conditions in an enum,
but such an enum is hard to maintain if your program links to a library in
which another developer has defined a separate enumeration. If you also 
want to use the newly available error conditions then it's less attractive to
update your implementation so that that's possible. 

The approach developed in this and the next section results in more flexible
(although still complex...) code. First two tt(ErrorCodeEnums) are developed:
they are the starting points when defining related error values. That these
values are related is then further developed by defining matching classes,
that are derived from the class tt(error_category) (see section
ref(ERRCAT)). Error conditions are used to associate error values with generic
causes of errors. Since error conditions may previously have been defined
(maybe by different developers) it is an interesting puzzle by itself to
figure out how multiple error conditions can flexibly be combined in one
program. This puzzle is solved by defining a class tt(ErrorCondition) that is
able to manage all error conditions.

The example used below focuses on the construction of a flight simulator. When
using the flight simulator itself several errors may be encountered (e.g., a
navigation beacon is out of range). Inside the cockpit, the system offers a
calculator, and here too specific errors may emerge: a non-existing function
may be requested, or parentheses of complex expressions might not
match. Whereas the former error is a specific calculator related error, the
latter is an error that's associated with bad user input, and thus three broad
categories of errors (i.e., error conditions) are distinguished: simulator-,
calculator-, and user-errors.

itemization(
it() Our first step consists of defining our own error enumerations: one
    related to the calculator and one related to the simulator:
    
    verbinsert(//enum examples/errcode/calculatorerror/calculatorerror.h)
    verbinsert(//enum examples/errcode/simulatorerror/simulatorerror.h)
    
    The class tt(std::error_code) is designed so that two pieces of
    information (the error value and its category) become available. The
    (int) error code through the member tt(value()), the error category
    through its member tt(category()).
    
it() Second, our intention is to let tt(error_code) accept
    tt(CalculatorError) and tt(SimulatorError) values using its
    tt(error_code(ErrorCodeEnum)) constructor as this allows us to
    retrieve error values and categories, using our own error code
    enumerations. 
    
    To achieve that the trait class ti(is_error_code_enum's) static member
    tt(value) must return tt(true) when provided with a
    value from our own error enumeration. This trait class.  Interestingly,
    defining the specializations of tt(std::is_error_code_enum) requires us to
    add code to the tt(std) namespace. Normally this is not allowed, but in
    this case it is. The bf(C++) standard states:

    quote(20.5.4.2.1 Namespace std
    
        The behavior of a C++ program is undefined if it adds declarations or
        definitions to namespace std or to a namespace within namespace std
        unless otherwise specified.
        
        A program may add a template specialization for any standard library
        template to namespace std only if the declaration depends on a
        user-defined type and the specialization meets the standard library
        requirements for the original template and is not explicitly
        prohibited.  
    ) 
   Here is the specialization for tt(CalculatorError); the one for
    tt(SimulatorError) is defined analogously:
    
  verbinsert(//trait examples/errcode/calculatorerror/calculatorerror.h)
    
    This completes the definition of our own error enumerations, which are
    now `promoted' to tt(ErrorCodeEnums).
    
it() Third, one of the constructors of tt(error_code) objects expects, in
    addition to an error value (an tt(int)) an tt(error_category)
    reference. Although the member template constructor merely requires an
    tt(ErrorCodeEnum) value, in fact it also needs an tt(error_category)
    object. That constructor normally casts the tt(ErrorCodeEnum) value to an
    tt(int), and constructs the tt(error_code) by also specifying a fitting
    tt(error_category). Therefore, a class matching the tt(ErrorCodeEnum) is
    usually derived from tt(error_category). Deriving a class from
    tt(error_category) is covered in the next section.
)

