&g == &(e.TheGrid())
.
Here E might be a model of
Grid Element,
Grid Function or the like.
Concepts are not a part of the C++ language; there is no way to declare a concept in a program, or to declare that a particular type is a model of a concept.
This is a very general definition, which must often be refined for practical purposes. However, the case of cells with holes (sometimes used in geometric modeling) is not covered by the definition.
This property excludes for example isolated vertices, or `free' edges (if the dimension is at least 2).
In generic algorithms, this serves as a placeholder for the actual implementations of grid_function for concrete element types E. For example, total grid functions for the Complex2D grid type are implemented by using vectors for the element types Complex2D::Vertex and Complex2D::Cell, and by using hash tables for the element type Complex2D::Edge:template<class E, class T> class grid_function<E,T> {};
template<class T> grid_function<Complex2D::Vertex, T> : public grid_function_vector<Complex2D::Vertex, T> { // repeat constructors }; template<class T> grid_function<Complex2D::Cell, T> : public grid_function_vector<Complex2D::Cell, T> { // repeat constructors }; template<class T> grid_function<Complex2D::Edge, T> : public grid_function_hash<Complex2D::Edge, T> { // repeat constructors };
A poset is bounded if there are unique minimal and maximal elements ^0 and ^1. A chain is a totally ordered subset of a poset. A bounded poset is called graded if every maximal chain has the same length (its number of elements minus 1). For a <= b, the interval [a,b] is the set of all elements in between:
[a,b] = { c in S | a <= c <= b }If S is graded, the rank of a in S is the length of a maximal chain in [^0,a].
The poset of a grid G can be made into a bounded one by adjoining the improper elements ^0 = Ø and ^1 = |G|, with dimensions -1 and d+1.
Here the class template vector publishes value_type and iterator, which can be used in another component:template<class T> class vector { public: typedef T value_type; typedef T* iterator; ... };
Another way to look at it is to say that vector<T> defines a mapping from type vector<T> to a set of associated type like vector<T>::iterator.template<class Container> void f(Container const& C, Container::value_type const& t) Container::iterator i = C.begin(); // ...
A different and somewhat more flexible way of achieving this is using so called traits classes, which makes use of several different such mappings for a given type possible. For this purpose, responsibility for the type definitions is delegated to a separate class, the traits class.
If the algorithm f above continues to be parameterized by C alone, not much changes, only the occurences of C::iterator has to replaced by container_traits<C>::iterator. On the other hand, one might imagine a counted iterator, which counts the number of increments. It would not be easy to introduce this without traits. However, we can use an additional traits parameter to the algorithm f:template<class C> struct container_traits {}; // default: empty // specialize for vectors template<class T> struct container_traits< vector<T> > { typedef T value_type; typedef T* iterator; // ... };
Now it is possible to introduce counted iterators, without any change to the algorithm implementation:template<class Container, class Traits> void f(Container const& C, Container::value_type const& t, Traits const&) Traits::iterator i = C.begin(); // ...
In the grid component framework, the template grid_types<> plays exactly the rôle of container_traits<> above.template<class C> struct counted_traits typedef C::value_type value_type; // use same value type typedef counted_iterator<C::iterator> iterator; // ... ; // use f, count increments MyContainer myc; typedef counted_traits<MyContainer> my_traits; f(my_c, t, my_traits());
A similar effect could be achieved by deriving from the container class, or defining a wrapper class with a delegation mechanism, which would contain the changed typedefs. However, this would not work for built-in types, and also not for aggregations (containers of containers), because there is no way of changing the type of contained items.