NABLA  Nabla Ain't Basic Linear Algebra
storage Struct Reference

Storage tag. More...

Detailed Description

Storage tag.

Requirements:
Expressions tagged with storage must be actual storage types. This implies that the object must be:
  • assignable (you can assign an expression to this object);
  • swappable in an efficient way;
  • mutable (you can change elements); this item also implies that you can get elements.
Additionally it is expected that a storage object is not aliased with other storage objects, that is modification of an arbitrary object does not affect this object.

Typically actual storage types like matrix or vector are tagged this way.

Storage Concept Description

Formally this concept can be thought of as a refinement of tag::reference .

Here is a concept description of a matrix storage class.

class type_id : public expression_id<value_type_id, type_id, tag::storage >
{
public:
//Type of elements manipulated by this class.
typedef value_type_id value_type;
//Reference to value type, typically 'value_type&'.
typedef implementation_defined reference;
//Reference to constant value type, typically 'const value_type&'.
typedef implementation_defined const_reference;
//Default constructor.
type_id();
//Copy constructor with ordinary semantics.
type_id(const type_id&);
//Copy construction from expression_id object.
template<typename expr_t, typename tag_t>
type_id(const expression_id<value_type, expr_t, tag_t>&);
//Copy assignment operator.
type_id &operator=(const type_id&);
//Copy assignment from expression_id object.
template<typename expr_t, typename tag_t>
type_id &operator=(const expression_id<value_type, expr_t, tag_t>&);
//Subscript operator.
reference operator()(size_t row, size_t col);
//Subscript operator.
const_reference operator()(size_t row, size_t col) const;
//Returns number of rows.
size_t rows() const;
//Returns number of columns.
size_t cols() const;
//Non throwing swap operation.
void swap(type_id&);
};

And here is one for a vector storage class.

class type_id : public expression_id<value_type_id, type_id, tag::storage >
{
public:
//Type of elements manipulated by this class.
typedef value_type_id value_type;
//Reference to value type, typically 'value_type&'.
typedef implementation_defined reference;
//Reference to constant value type, typically 'const value_type&'.
typedef implementation_defined const_reference;
//Default constructor.
type_id();
//Copy constructor with ordinary semantics.
type_id(const type_id&);
//Copy construction from expression_id object.
template<typename expr_t, typename tag_t>
type_id(const expression_id<value_type, expr_t, tag_t>&);
//Copy assignment operator with ordinary semantics.
type_id &operator=(const type_id&);
//Copy assignment from expression_id object.
template<typename expr_t, typename tag_t>
type_id &operator=(const expression_id<value_type, expr_t, tag_t>&);
//Subscript operator.
const_reference operator()(size_t i) const;
//Returns size of vector.
size_t size() const;
//Non throwing swap operation.
void swap(type_id&);
};

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

m(0, 0) = some_value;

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:

template<typename expr_t, typename tag_t>
my_matrix(const matrix_expression<value_type, expr_t, tag_t> &e)
{
const expr_t &ref = get_matrix(e); //acquiring reference to underlying object
this->resize(ref.rows(), ref.cols()); //resizing storage of this object
for (size_t i = 0; i<ref.rows(); ++i)
for (size_t j = 0; j<ref.cols(); ++j)
(*this)(i, j) = ref(i, j); //copying values
return *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.

See Also
reference, expression

Definition at line 846 of file matrix.h.


The documentation for this struct was generated from the following file: