section 4C — variable versus constant.
home

The mat_gen_dim notion of what "constant" means may not be intuitive. Here is a summary of what functions can be called from what matrix types:

var_matrix var_matrix const con_matrix con_matrix const
assign_form
operator=
yesnoyesno
get_vector
count
get_form
get
con_ref
yesyesyesyes
set
var_ref
linear_fill
random_fill
yesyesnono

With the following definitions, where the hash mark represents suitable parameters:

    var_matrix< # > mat_avar { # };
    con_matrix< # > mat_acon { # };
    var_matrix< # > mat_bvar { # };
    con_matrix< # > mat_bcon { # };
all four of the following assignments are legal:
    mat_avar = mat_bvar;
    mat_acon = mat_bvar;
    mat_avar = mat_bcon;
    mat_acon = mat_bcon;
The case of mat_avar = mat_bcon requires explanation. After assignment is complete, if mat_avar tries to change one of its components, cloning will take place and mat_bcon will not be affected.

As always, assignment to a const is prohibited:

    var_matrix< # > const mat_avar { # };
    con_matrix< # > const mat_acon { # };

    mat_avar = /* anything */; // ILLEGAL
    mat_acon = /* anything */; // ILLEGAL

A non-const container can initialize a const container if the components are of precisely the same type, but a container of non-const objects cannot portably initialize a container of const objects, although it would seem to make sense:

    var_matrix < double >         vm1 {form {blt{1,4}}};
    var_matrix < double > const   vm2 {vm1};   // LEGAL
    var_matrix < double   const > vm3 {vm1};   // ILLEGAL
Along the same lines:
    std::vector < double >         sv1 {1.0,2.0,3.0};
    std::vector < double > const   sv2 (sv1);  // LEGAL
    std::vector < double   const > sv3 (sv1);  // ILLEGAL

Within mat_gen_dim, the con_ prefix implies constancy of matrix components. In a sense, then, con_matrix<any_type> has a meaning similar to var_matrix<any_type const>. However, a limitation arises in that a mat_gen_dim matrix is ultimately stored as a std::vector, and the C++ Standard Library requires that vector components be assignable. (Some implementations do not report an error until, in the deeper workings of std::vector, a component assignment is actually attempted. Thus some programs with a std::vector<any_type const> may run, but not portably.)

Because any_type const is patently not assignable, something like var_matrix<any_type const> would not generally work without contortions of code, and mat_gen_dim does not attempt it as the program is already complicated enough.

In response to the requirement of assignability for the component type, the Standard Library provides std::vector<any_type>::const_iterator for the programmer who wants to iterate while ensuring the constancy of components. This is in place of converting a std::vector<any_type> to a std::vector<any_type const> and then creating a std::vector<any_type const>::iterator.

In short, con_matrix exists for the same reason as const_iterator. More, the family of lenses introduced in section 6 blurs the difference between matrices and iterators.


Here is a table of analogy among mat_gen_dim, the iterators of the Standard Library, and plain old pointers:

mat_gen_dimStandard Libraryplain old pointers
var_matrix:
  • It can modify its components.
  • It can itself be modified, for instance by assigning to it the value of another var_matrix, or by calling assign_form on it.
iterator:
  • It can modify the object to which it points.
  • It can itself be modified, for instance by assigning to it the value of another iterator, or by causing it to point to a different object.
int * ip;
var_matrix const:
  • It can modify its components.
  • It cannot itself be modified.
iterator const:
  • It can modify the object to which it points.
  • It cannot itself be modified.
int * const ipc;
con_matrix:
  • It cannot modify its components.
  • It can itself be modified, for instance by assigning to it the value of another con_matrix, or by calling assign_form on it.
const_iterator:
  • It cannot modify the object to which it points.
  • It can itself be modified, for instance by assigning to it the value of another const_iterator, or by causing it to point to a different object.
int const * icp;
con_matrix const:
  • It cannot modify its components.
  • It cannot itself be modified.
const_iterator const:
  • It cannot not modify the object to which it points.
  • It cannot itself be modified.
int const * const icpc;