Question

Can I have a vector filled with both, type A and B? I will fill it only with one type, so I am always sure, what I will get out of it. But it would make many things very easy for me, if I can define the vector once.

type T is tagged null record;

type A is new T with
   record
      x : Integer;
   end record;

type B is new T with
   record
      y : Integer;
   end record;

package Some_Vector is new Ada.Containers.Indefinite_Vectors (
   Index_Type => Positive,
   Element_Type => T <- ???
);
Was it helpful?

Solution

You can say:

package Some_Vector is new Ada.Containers.Indefinite_Vectors (
   Index_Type => Positive,
   Element_Type => T'Class
);

Some_Vector is now able to hold elements of type T or any type derived from it, including A or B. There's no requirement that all the elements have to be of the same type, as long as they're all derived from T; so if you don't really care whether this property is enforced, the above should work. If you really want the compiler to enforce that all elements are the same type, then you should simply declare two packages, A_Vector and B_Vector, for vectors of the two types; but then there's no way to write a "class-wide" type name that could refer to either an A_Vector or a B_Vector.

If you really want to combine both--have a vector type that could refer either to a vector of A or a vector of B, but still enforce that all elements of the vector have the same type, then I think this could be done if you define your own vector type and perform the needed check at run time, but it could get complicated. This compiles, but I haven't tested it:

generic
    type Elem is new T with private;
package Sub_Vectors is
    type Sub_Vector is new Some_Vector.Vector with null record;

    overriding
    procedure Insert (Container : in out Sub_Vector;
                      Before    : in     Some_Vector.Extended_Index;
                      New_Item  : in     T'Class;
                      Count     : in     Ada.Containers.Count_Type := 1)
        with Pre => New_Item in Elem;
end Sub_Vectors;

package body Sub_Vectors is
    procedure Insert (Container : in out Sub_Vector;
                      Before    : in     Some_Vector.Extended_Index;
                      New_Item  : in     T'Class;
                      Count     : in     Ada.Containers.Count_Type := 1) is
    begin
        Some_Vector.Insert
            (Some_Vector.Vector(Container), Before, New_Item, Count);
    end Insert;
end Sub_Vectors;

Unfortunately, you'd have to override every Insert and Replace_Element operation that could put an element into the vector. After you do all this, though, you can instantiate Sub_Vectors with Elem => A and with Elem => B, and the class Some_Vector.Vector'Class would be a class-wide type that would include both Sub_Vector types in the instance packages.

OTHER TIPS

If you really want the compiler to enforce that all elements are the same type, then you should simply declare two packages, A_Vector and B_Vector, for vectors of the two types; but then there's no way to write a "class-wide" type name that could refer to either an A_Vector or a B_Vector.

You can, however, have a vector that points only to the A or B subtrees of the hierarchy:

type T is tagged null record;
type A is new T with null record;
type B is new T with null record;
type C is new T with null record;

type TAB is access all T'Class
  with Dynamic_Predicate => 
     TAB = null or else
    (TAB.all in A'Class or TAB.all in B'Class);

Above yields the TAB Type which must be a [pointer to] an A'Class or B'Class, which you should be able to use in your vector. -- The only problem I've run into is you have to use GNAT's 'Unchecked_Access to get the access values of objects (due, I think, to my quick and dirty testing).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top