Sunday 15 July 2012

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? -



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.

question

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):

the internal base of operations class's apply called on pointer base of operations class runtime type of derived class. the phone call dispatched derived class, knows type of stored object.

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.

attempts

here 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.

attempt 1 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 on genericfunctioncall, 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