c++11 - multiple inheritance with concept-based polymorphism c++ -


using concept-based polymorphism focuses on using value semantics , type erasure implement type polymorphism, how 1 implement multiple inheritance?

an example of interface follows. defines type, serializable, require functions serialize , size appropriate signature.

#include <iostream> #include <memory>  using namespace std;  class serializable { public:   template <typename t>   serializable(t x) : self_(new model<t>(move(x)))   { }    friend size_t serialize(const serializable& x, uint8_t* buffer, size_t buffersize) {     x.self_->serialize_(buffer, buffersize);   }   friend size_t size(const serializable& x) {     x.self_->size_();   }  private:   struct concept {     virtual ~concept() = default;     virtual size_t serialize_(uint8_t*, size_t buffersize) const = 0;     virtual size_t size_() const = 0;   };   template <typename t>   struct model : concept {     model(t x) : data_(move(x)) { }     size_t serialize_(uint8_t* buffer, size_t buffersize) const     { serialize(data_, buffer, buffersize); }     size_t size_() const     { size(data_); }      t data_;    };    shared_ptr<const concept> self_; }; 

a class implements interface shown below. instead of directly inheriting pure virtual functions, uses same function names. myclassb later used , identical implementation, different name.

class myclassa { public:   myclassa(const string& name) :     name_(name)   { }    friend size_t serialize(const myclassa& x, uint8_t* buffer, size_t buffersize);   friend size_t size(const myclassa& x); private:   const string name_; };  size_t serialize(const myclassa& x, uint8_t* buffer, size_t buffersize) {   size_t bytestowrite = size(x);   if(bytestowrite <= buffersize) {       memcpy(buffer, x.name_.c_str(), bytestowrite);     } else {       bytestowrite = 0;     }   return bytestowrite; }  size_t size(const myclassa& x) {   x.name_.length(); } 

in addition, same signature created vector.

size_t size(const vector<serializable>& x) {   size_t totalsize = 0;   (auto& e : x) {     totalsize += size(e);   }   return totalsize; }  size_t serialize(const vector<serializable>& x, uint8_t* buffer, size_t buffersize) {   size_t bytestowrite = size(x);   size_t offset = 0;   if(bytestowrite <= buffersize) {       (auto& e : x) {         offset += serialize(e, buffer + offset, buffersize - offset);       }     } else {       bytestowrite = 0;     }   return bytestowrite; } 

to use type, myclassa, myclassb , vector, client-side code below creates objects, adds them vector , prints them.

int main() {   vector<serializable> channel;   uint8_t buffer[30] = {};    myclassa myclassa("hello world!");   serialize(myclassa, buffer, sizeof buffer);   cout << buffer << endl;    cout << "-------------------" << endl;    channel.emplace_back(myclassa(" apples"));   channel.emplace_back(myclassb(" oranges"));   serialize(channel, buffer, sizeof buffer);   cout << buffer << endl;    cout << "-------------------" << endl;    cout << size(channel) << endl;    cout << "-------------------" << endl;    vector<serializable> channel2;   channel2.emplace_back(channel);   channel2.emplace_back(channel);   serialize(channel2, buffer, sizeof buffer);   cout << buffer << endl; } 

the code has been prepared in following repository. build run scons in root directory: https://github.com/moritz89/type-erasure-test?files=1

back original question, possible create additional interfaces, e.g., reporterror or client, define functions have implemented , can unified create multiple inheritance structures?

you can this, need change approach bit don't end needlessly duplicating. first, need simple empty_model class:

template <typename t, typename ... <class> models> struct empty_model : models<empty_model> {   model(t x) : data_(move(x)) { }   t data_; }; 

this has whatever code necessary build proxy t. next, have turn our per-concept models things only handle forwarding interface, not ownership, via crtp:

  // still nested in serializable, or whatever concept   template <typename d>   struct model : concept {     size_t serialize_(uint8_t* buffer, size_t buffersize) const     { serialize(static_cast<const d&>(*this).data_, buffer, buffersize); }     size_t size_() const     { size(static_cast<const d&>(*this).data_); }   }; 

so, each concept, writing nested model class bit different, far amount of boiler plate not larger. use typedefs create actual models want:

template <class t> using serializable_model  = empty_model<t, serializable::model>;  template <class t> using my_model = empty_model<t, serializable::model, reporterror::model>; 

the last thing need change concept have constructor accepts actual shared_ptr:

serializable(shared_ptr<const concept> x) : self_(move(x)) {} 

so in principle write concrete class, foo, , like:

auto f = make_shared<my_model<foo>>(foo{}); 

remember (yeah, it's getting hard...) my_model inherit nested model classes (suitably templated), inherit base concepts. means my_model<foo> grandson of serializable::concept, f implicitly convert can this:

serializable s(f); 

all said: while sean parents talks brilliant (yes easy recognize), lot of work, complexity , boilerplate. in experience, 99% of time in real code, better writing off interface, , writing concrete type directly inherits them. i'd make sure specific problem benefits before going down rabbit hole.


Comments

Popular posts from this blog

ubuntu - PHP script to find files of certain extensions in a directory, returns populated array when run in browser, but empty array when run from terminal -

php - How can i create a user dashboard -

javascript - How to detect toggling of the fullscreen-toolbar in jQuery Mobile? -