AnyPtr

Files CCore/inc/AnyPtr.h CCore/src/AnyPtr.cpp

Two similar classes implement a "polymorphic pointer" type. They can store multiple type pointers. The pointee type list is the template parameter list. AnyPtr stores pointers to non-constants and AnyPtr_const stores pointers to constants.


template <class ... TT>
class AnyPtr
 {
   ....

  public:
  
   // constructors

   AnyPtr() noexcept;
   
   AnyPtr(NothingType) : AnyPtr() {}
   
   AnyPtr(std::nullptr_t) : AnyPtr() {}

   template <class T>
   AnyPtr(T *ptr);
   
   // methods

   boolable operator + () const;
   
   bool operator ! () const;
   
   template <class T>
   bool hasType() const;
   
   template <class T>
   T * castPtr() const;

   template <class FuncInit,class ... SS>
   void apply(FuncInit func_init,SS && ... ss) const;
   
   template <class T,class FuncInit>
   void applyFor(FuncInit func_init) const;

   // Binary
   
   template <class Ret,class FuncInit>
   static Ret Binary(AnyPtr<TT...> a,AnyPtr<TT...> b,FuncInit func_init);

   // print object
   
   template <class P>
   void print(P &out) const;
 };

template <class ... TT>
class AnyPtr_const
 {
   ....

  public:
  
   // constructors

   AnyPtr_const();
   
   AnyPtr_const(NothingType) : AnyPtr_const() {}
   
   AnyPtr_const(std::nullptr_t) : AnyPtr_const() {}

   template <class T>
   AnyPtr_const(const T *ptr);
   
   // methods

   boolable operator + () const;
   
   bool operator ! () const;
   
   template <class T>
   bool hasType() const;
   
   template <class T>
   const T * castPtr() const;
   
   template <class FuncInit,class ... SS>
   void apply(FuncInit func_init,SS && ... ss) const;
   
   template <class T,class FuncInit>
   void applyFor(FuncInit func_init) const;

   // Binary
   
   template <class Ret,class FuncInit>
   static Ret Binary(AnyPtr_const<TT...> a,AnyPtr_const<TT...> b,FuncInit func_init);

   // print object
   
   template <class P>
   void print(P &out) const;
 };

Default constructor creates a null object. There are also constructors from NothingType words and nullptr literal.

The last implicit constructor creates an object with the given pointer stored. The type T must be a type from the template parameter list. Even if the pointer is null, the object is not null: it remembers the pointer type.

operator + and operator ! can be used to check, if the pointer is non-null.

hasType() can be used to check the type of the pointer. The template parameter T must be from the list TT.

castPtr() returns the original pointer of the given type T, or null if the stored pointer has another type.

The method apply() applies the given functor, using the Functor Init Pattern, to the stored pointer. It does nothing for the null object, but if it is not null, the proper variant of the functor is applied to the initial pointer. The functor must be polymorphic and capable to handle all possible pointer types. Extra arguments are passed as extra arguments to the functor call.

An example:


int *a=....;

AnyPtr<short,int,long> ptr=a;

ptr.apply(func_init); // func_init -> func ; calls func(a);

ptr.apply(func_init,a1,a2,a3); // func_init -> func ; calls func(a,a1,a2,a3);

applyFor() applies the functor to the pointer of the given type. If the object is null or stores a pointer of another type, this method does nothing.

AnyPtr can print the pointed object. If the pointer is null, the "(null)" is printed, otherwise the object. Printing is implemented with the following functor:


template <class P>
class PrintAnyObj
 {
   P &out;
   
  public: 
  
   explicit PrintAnyObj(P &out_) : out(out_) {}
  
   template <class T>
   void operator () (T *obj)
    {
     Putobj(out,*obj);
    }
 };

The static method Binary is used with two any-pointers. If pointer types are different then the return object is constructed as Ret(a.type,b.type), so you can handle this case separately. Otherwise if both any-pointers are not null objects, then the functor with two elaborated pointers is called. Finally, Ret() is returned if both arguments are null. An example:


using Type = AnyPtr<int,double> ;

int *a=....;
double *b=....;
int *c=....;

Type::Binary<Ret>(Type(),Type(),func); // return Ret();

Type::Binary<Ret>(Type(a),Type(b),func); // return Ret(1,2);

Type::Binary<Ret>(Type(a),Type(c),func); // return func(a,c);

This method is useful for a comparison implementation.

The global function ElaborateAnyPtr is another great way to demultiplex any-pointers.


template <class T,class ... SS>
void ElaborateAnyPtr(T &obj,SS && ... ss);

This function simply calls obj(ss...) with the given arguments. But if one of the argument is AnyPtr, then the correspondent pointer is extracted and passed instead. If the pointer object is null, there will be no call. An example:


int *a=....;
double *b=....;

ElaborateAnyPtr(obj,AnyPtr<int,double>(a),AnyPtr<int,double>(b),3,4,5); // calls obj(a,b,3,4,5);