[Notes] C++ Idiom : Type Erasure
22 May 2023-
Design Problem : Expose a function F with a argument A (any type) which is not polymorphic but has polymorphic callable interface inside A, which is called inside F.
- A can be CV qualified too.
-
F can not be template function since we need uniform
void F(Atype A)
for every type it is used for. - Dynamic Polymorphism = Different objects at runtime behave via single “interface”
- Take “interface” , use any object dynamic or static
- e.g. In C, void* is generic object
void qsort(void *ptr, std::size_t count, std::size_t size, cmp);
-
In C++, Templates! ==> TYPE ERASURE APPLIES WHEN GENERICS is USED!
-
Why erase types?
- We have interface
doWork(Object obj)
, which can accept any Type of Object and simply doWork without losing strong typing - Mostly useful for library development
- We have interface
3 Steps of Type Erasure Solution
1) Interface that isn’t tied to concrete type
#include<bits/stdc++.h>
class AbstractMojo{
virtual void justMojo() =0 ; // Have Delegation
virtual ~AbstractMojo() = default;
};
// How to call?
void DoMojo(AbstractMojo& jomo);
- One Parent Abstract class per interface!
- concrete classes has to derive from
AbstractMojo
, what if Concrete classes are “Closed for update” - Requirement : Typewise function call -> function template
class AbstractMojo{
virtual void justMojo() =0 ; // Have Delegation
virtual ~AbstractMojo() = default;
};
// How to call?
template<typename T>
void DoMojo(T& jomo);
2) Erase Type T
- No such thing as removing type (like assignming to void*) , we can add class abstraction
class AbstractMojo{
virtual void justMojo() =0 ; // Have Delegation
virtual ~AbstractMojo() = default;
};
class Mojo : AbstractMojo { // Provide interface
public:
template<typename T> // Templatized
explicit Mojo(T mT) :{}
void justMojo() override { // Provide uniform interface
mT.justMojo();
}
//>>>> mT
}
// How to Call
void DoMojo(Mojo jomo); // Type Erased!
- Storing Erased Type
- Move T storage to wrapper, it knows type, it has to call interface, it derives from AbstractMojo
#include<bits/stdc++.h>
class AbstractMojo{
public:
virtual void justMojo() =0 ; // Have Delegation
virtual ~AbstractMojo() = default;
};
template<typename T>
class MojoWrapper : AbstractMojo { // Provide interface
T mT;
public:
explicit MojoWrapper(T nT) : mT(nT) {}
void justMojo() override { // Provide uniform interface
mT.justMojo();
}
};
class Mojo {
std::unique_ptr<AbstractMojo> mWTPtr ; // STORE ABSTRACT Level 1
public:
template<typename T> //still Templatized
explicit Mojo(T mT) {
mWTPtr = std::make_unique<MojoWrapper<T>>(mT); // CONSTRUCT CONCRETE , STORE in WRAPPER
}
void justMojo(){ // Provide uniform interface but not override
mWTPtr->justMojo();
}
};
// How to Call
void DoMojo(Mojo jomo); // Type Erased!
- Example of
std::function