c++ - How can I make a class that type-erases objects until a function is called on them without specifying the list of possible functions up front? -
background
the title sounds confusing, allow me explain. first of all, here minimal version of implementation, can follow along concepts more easily. if you've seen of sean parent's talks, you'll know came way abstract polymorphism, allowing code such this:
std::vector<drawable> figures{circle{}, square{}}; (auto &&figure : figures) {draw(figure);}
notice there no pointers or anything. calling draw
on drawable
phone call appropriate draw
function on contained object without type of object beingness accessible. 1 major downside similar classes drawable
have written each task. i'm trying abstract bit function not have known class. current solution follows:
std::vector<applicator<draw>> figures{circle{}, square{}}; (auto &&figure : figures) {figure.apply(draw{});}
here, draw
functor operator()(circle)
, opeator()(square)
, or generic version. in way, sort of visitor pattern implementation. if wanted also, say, print name of each figure, applicator<draw, printname>
. when calling apply
, desired function chosen.
my implementation works passing boost::variant
of callable types virtual function , having visit variant , phone call function within. overall, implementation acceptable, haven't yet thought much allowing number of parameters or homecoming type, allow lone ones differ function function.
i spent days trying think of way have work without making applicator
template. ideally, utilize more similar this. sake of simplicity, assume functions called must have signature void(objecttype)
.
//for added type strictness, create applicator<figure> , have //using figure<struct circle> = circle; etc std::vector<applicator> figures{circle{}, square{}}; (auto &&figure : figures) {figure.apply(draw{});} //or .apply(draw); if can
the problem comes downwards fact type of object can obtained within function called on it. internally, class uses virtual functions, means no templates. when apply
called, here's happens (identical sean's talks):
so time have object, function phone call must reduced single type known within class both knows function phone call , takes object. cannot life of me come way this.
attemptshere couple of failed attempts can see why find difficult:
the premise both of first 2 have type holds function phone call minus unknown first argument (the stored object). need @ to the lowest degree templated on type of callable object. using sean parent's technique, it's easy plenty create functioncall<f>
class can stored in genericfunctioncall
, much circle
in figure
. genericfunctioncall
can passed virtual function, whereas other cannot.
apply()
called known callable object type. the type of callable object used create functioncall<type>
, store type-erased genericfunctioncall
. this genericfunctioncall
object passed virtual apply
function. the derived class gets phone call object , has object used first argument available. for same reason of virtual functions not beingness allowed templates, genericfunctioncall
phone call necessary function on right functioncall<type>
, not forwards first (stored object) argument. attempt 2 as continuation of effort 1:
in order pass stored object function called ongenericfunctioncall
, stored object type-erased genericobject
. one of 2 things possible: a function called , given proper functioncall<type>
, has genericobject
give it, type unknown outside of function called on it. recall function cannot templated on function phone call type. a function called , given proper t
representing stored object, has genericfunctioncall
extract right function phone call type from. we're started in derived class's apply
function. attempt 3 take known type of callable object when calling apply
, utilize create stores function can phone call known stored object type (like std::function
). type-erase boost::any
, pass virtual function. cast appropriate type when stored object type known in derived class , pass object in. realize whole approach requires stored object type known when calling apply
. are there bright ideas out there how turn class 1 doesn't need template arguments, can rather take callable object , phone call stored object?
p.s. i'm open suggestions on improve names applicator
, apply
.
this not possible. consider programme composed of 3 translation units:
// tu1.cpp void populate(std::vector<applicator>& figures) { figures.push_back(circle{}); figures.push_back(square{}); } // tu2.cpp void draw(std::vector<applicator>& figures) { (auto &&figure : figures) { figure.apply(draw{}); } } // tu3.cpp void combine() { std::vector<applicator>& figures; populate(figures); draw(figures); }
it must possible each tu translated separately, indeed in causal isolation. means @ no point there compiler simultaneously has access draw
, circle
, code draw
phone call circle::draw
can never generated.
c++ polymorphism c++14 type-erasure
No comments:
Post a Comment