wip writing adv. templ. errorcategory.yo

This commit is contained in:
Frank B. Brokken 2017-11-29 22:06:07 +01:00
parent af78351dfa
commit 1f9db0e5b4
5 changed files with 90 additions and 66 deletions

View file

@ -0,0 +1,68 @@
The tt(ErrorCodeEnums) developed in the previous section are the starting
points for two more classes, derived from the class tt(error_category) (see
section ref(ERRCAT).
Our own error category classes are designed as singleton classes, dervied from
tt(std::error_category), and merely have to implement their own tt(name,
message) and an tt(equivalent) function.
Associated with errors defined by tt(ErrorCodeEnums) are two textual items
(NTBSs): a verbal description of the error, and the name of the em(error
condition) to which the enum value belongs. E.g., associated with
tt(CalculatorError:::MissingParentheses) are the description tt("parentheses
don't match") and the error condition name tt("InputCond"). Those associations
are collected in a class template tt(CatMap), which has been derived from
tt(std::unordered_map). tt(CatMap)'s design is a rather straightforward,
offering a constructor accepting an tt(std::initializer_list):
verbinsert(-s4 //impl examples/errcode2/catmap/catmap.h)
As tt(ErrorCodeEnum)-values may have been randomly assigned (not using 0)
a tt(CapMap) offers fast access to the error's description and error condition
name.
To definine an error category class we take the following steps:
itemization(
it() First the class's interface is designed. The interface of the class
tt(CalculatorCategory) is shown here, the interface of
tt(SimulatorCategory) is analogously designed. Their setup is fairly
basic; being a singleton class its (default) constructor is private, and
a static member tt(instance) returns a reference to the class's sole
object. A second static member (tt(CatMap s_errors) is initialized with
tt(ErrorCodeEnum) values and their descriptions and error condition
names:
verbinsert(//class
examples/errcode2/calculatorcategory/calculatorcategory.h)
The member tt(instance) returns a reference to the singleton object,
initializing it the first time it is called:
verbinsert(//impl examples/errcode2/calculatorcategory/instance.cc)
The member tt(name) simply returns a short string naming the category
(tt("calculator") for the calculator category).
it() Next, the The class's tt(message) member is defined. It returns the
description matching values of the category's error code enum values.
error code and returns its description. Here is the definition of the
tt(message) member, and the initialization of the tt(CatMap s_errors)
static data member:
verbinsert(//impl examples/errcode2/calculatorcategory/messace.cc)
verbinsert(//impl examples/errcode2/calculatorcategory/data.cc)
it()
it() Fifth, we're now in position to actually create tt(error_code) objects
from tt(CalculatorError) enum values. For this we define the free function
tt(make_error_code(CalculatorError ce)):
verbinsert(//impl examples/errcode2/calculatorcategory/makeerrorcode.cc)
Now that tt(CalculatorErrc) is an tt(std::error_code) we can use it in our
programs. Here is a little program illustrating its use:
verbinsert(-a examples/errcode2/main.part);
In the next section using error conditions is covered in detail.
)

View file

@ -27,8 +27,8 @@ 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(ErrorSource) that
manages error conditions.
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
@ -45,7 +45,6 @@ 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/errcode2/calculatorerror/calculatorerror.h)
verbinsert(//enum examples/errcode2/simulatorerror/simulatorerror.h)
The class tt(std::error_code) is designed so that two pieces of
@ -55,18 +54,18 @@ it() Our first step consists of defining our own error enumerations: one
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
tt(error_code(ErrorCodeEnum)) constructor as this allows us to
retrieve error values and categories, using our own error code
enumerations.
To achieve this, the trait class ti(is_error_code_enum), must be
available for our error enumeration. This trait class's static member
tt(value) must return tt(true). 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:
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
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
@ -81,7 +80,7 @@ it() Second, our intention is to let tt(error_code) accept
Here is the specialization for tt(CalculatorError); the one for
tt(SimulatorError) is defined analogously:
verbinsert(//trait examples/errcode2/calculatorerror/calculatorerror.h)
verbinsert(//trait examples/errcode2/calculatorerror/.h)
This completes the definition of our own error enumerations, which are
now `promoted' to tt(ErrorCodeEnums).
@ -93,51 +92,7 @@ it() Third, one of the constructors of tt(error_code) objects expects, in
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
derived from tt(error_category).
Our own error category classes are designed as singleton classes and
merely have to implement their own tt(name, message) and one
tt(equivalent) function. tt(Message) members return descriptions matching
values of error code enums, and for that we use a tt(std::unordered_map),
for which the tt(typedef CatMap) is defined (since
tt(ErrorCodeEnum)-values may have been randomly assigned (not using 0) an
tt(unordered_map) offers fast access to the error's description and error
condition (see the next section) given its value). Here is the interface
of the class tt(CalculatorCategory):
verbinsert(//class
examples/errcode2/calculatorcategory/calculatorcategory.h)
As error category objects are singletons error categories can simply be
compared for (in)equality by comparing the addresses of their singleton
objects.
it() Fourth, the class's tt(name) member simply returns a short string naming
the category (tt("calculator") for the calculator category).
The class's tt(message) member locates the tt(CatMap) entry matching the
error code and returns its description. Here are the definitions of the
tt(message) member, of the member tt(instance) returning a reference to
the class's single object, and to the initialization of its tt(CatMap)
static data member:
verbinsert(//impl examples/errcode2/calculatorcategory/messace.cc)
verbinsert(//impl examples/errcode2/calculatorcategory/instance.cc)
verbinsert(//impl examples/errcode2/calculatorcategory/data.cc)
it() Fifth, we're now in position to actually create tt(error_code) objects
from tt(CalculatorError) enum values. For this we define the free function
tt(make_error_code(CalculatorError ce)):
verbinsert(//impl examples/errcode2/calculatorcategory/makeerrorcode.cc)
Now that tt(CalculatorErrc) is an tt(std::error_code) we can use it in our
programs. Here is a little program illustrating its use:
verbinsert(-a examples/errcode2/main.part);
In the next section using error conditions is covered in detail.
)
usually derived from tt(error_category). Deriving a class from
tt(error_category) is covered in the next section.
)

View file

@ -16,11 +16,10 @@ class CalculatorCategory: public std::error_category
public:
static CalculatorCategory &instance();
bool equivalent(std::error_code const &ec, int condNr) const noexcept
override;
char const *name() const noexcept override;
std::string message(int ce) const override;
bool equivalent(std::error_code const &ec, int condNr) const noexcept
override;
private:
CalculatorCategory() = default;
};

View file

@ -4,6 +4,7 @@
#include <unordered_map>
#include <tuple>
//impl
template <class Enum>
class CatMap: public std::unordered_map<
Enum,
@ -18,9 +19,11 @@ class CatMap: public std::unordered_map<
};
template <class Enum>
CatMap<Enum>::CatMap(std::initializer_list<typename Map::value_type> const &list)
CatMap<Enum>::CatMap(
std::initializer_list<typename Map::value_type> const &list)
:
Map{ list }
{}
//=
#endif

View file

@ -15,11 +15,10 @@ class SimulatorCategory: public std::error_category
public:
static SimulatorCategory &instance();
bool equivalent(std::error_code const &ec, int condNr) const noexcept
override;
char const *name() const noexcept override;
std::string message(int ce) const override;
bool equivalent(std::error_code const &ec, int condNr) const noexcept
override;
private:
SimulatorCategory() = default;
};