NABLA
Nabla Ain't Basic Linear Algebra
|
Storage tag. More...
Storage tag.
storage
must be actual storage types. This implies that the object must be:Typically actual storage types like matrix
or vector
are tagged this way.
Formally this concept can be thought of as a refinement of tag::reference
.
Here is a concept description of a matrix storage class.
And here is one for a vector storage class.
These are the minimum set of entities for storage types. This means that all the listed members are mandatory and must be implemented. But there can be other useful members as well. The idea behind this set is to require as little as possible but at the same time to make the interface complete. Lets clarify every element of these declarations.
type_id
is the name of the class, e.g. matrix
or vector
.
The class publicly inherits expression_id
which is the name of a specific expression. For matrix expressions it can be matrix_expression
or related template classes. For vector expressions it can be vector_expression
and its relatives. The template class is instantiated with appropriate arguments, e.g. matrix_expression
must be instantiated with element type (value_type_id
), the class itself (type_id
) and tag (here tag::storage
).
The value_type
typedef represents type of elements manipulated by the class, it should be defined as value_type_id. For example matrix<double>
defines value_type
as double
.
The reference
typedef represents type of reference to element. Typically it is defined as value_type&
. Alternatively it may be defined as special utility class which provides access to elements in the object's internal structure. In either way it must model semantics of an "lvalue" so user were able to write something like
The const_reference
typedef represents type of reference to constant element. Typically it is defined as const value_type&
. But it can either be defined, say, as value_type
or some other special utility class similar to mentioned above. Anyway it must model semantics of an "rvalue".
The class must provide default constructor so an arbitrary routine can create an instance of an object and work with it (possibly assign to it).
The copy constructor with ordinary semantics must be defined in order to, well, copy construct objects.
The more interesting case is the constructor taking an expression as its argument. The thing is that it is not known about internal structure of an entity and its invariants so one hardly can properly construct an arbitrary entity. But the type is aware of how to construct itself and in the same time the expression mechanism provides regular interface to objects. So to abstract from objects' structure and invariants a type is made responsible for constructing itself provided an appropriate expression. A simple implementation of my_matrix
copy construction from matrix expression can look like this:
I've omitted implementation details but I hope you've got the point. Here resize()
member function is used however it is not a part of the interface implied by tag::storage
. By the way, here we use a set of interface entities promised by tag::expression
for the expression as the least restrictive. And it is a good idea to treat expressions as if they were tagged with tag::expression
unless you explicitly specify it in function definition.
Copy assignment operator and copy assignment from an expression are fully analogous to just discussed copy constructors.
Subscript operator (which is actually a function call operator) provides access to elements. The only difference in that for matrix expressions and vector expressions is the number of arguments taken by function. It should be obvious that the only argument for vector is the index of an element in it. The first argument for matrix version represents the index of the row in which an element is situated and the second argument is the index of the column containing an element (or the index in the row).
rows()
and cols()
return number of rows and columns of a matrix respectively. size()
returns number of elements in a vector.
Finally swap
() member function swaps contents of two objects. This operation should not throw any exceptions. Non-member function swap()
is implemented in terms of this function.