Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

the best design for mapping enums to const classes

I have this example that works :
I create an object that implements "PartInterface" for each value of the enum and add them in a map. But I don’t find this satisfactory, because everything could be inferred at compile time rather than at runtime.
Is there a more elegant way to do this in c++ 11?
Another solution would be to build the "YearPart", "MonthPart" and "DayPart" objects at each call of the "get" function,
but it seems to me less efficient…

#include <iostream>

#include <map>
#include <memory>

struct Date{
    int year;
    int month;
    int day;
};

class PartInterface{
public:
    virtual const std::string & getName()const=0;
    virtual int getValue(const Date& d)const=0;
    virtual ~PartInterface(){}
};

class Part : public PartInterface{
public:
    Part(const std::string& name):_name(name){}

    const std::string & getName()const{
        return _name;
    }
    virtual int getValue(const Date& d)const=0;
    
private:
    std::string _name;
};

class YearPart : public Part{
public:
    YearPart():Part("year"){}
    int getValue(const Date& d)const{
        return d.year;
    }
};

class MonthPart : public Part{
public:
    MonthPart():Part("month"){}
    int getValue(const Date& d)const{
        return d.month;
    }
};

class DayPart : public Part{
public:
    DayPart():Part("day"){}
    int getValue(const Date& d)const{
        return d.day;
    }
};

enum DatePart{
    Year,
    Month,
    Day
};

class Parts{
public:
    Parts(){
        _map[Year].reset(new YearPart());
        _map[Month].reset(new MonthPart());
        _map[Day].reset(new DayPart());
    };
    
    const PartInterface& get(const DatePart& date_part)const{
        return * (_map.find(date_part)->second);
    }
    
private:
    std::map<DatePart, std::unique_ptr<PartInterface> > _map;
};

int main() {
  Date d({2016, 7, 23});
  const Parts parts;
  std::cout << "Date " 
    << parts.get(Year).getValue(d) << " " 
    << parts.get(Month).getValue(d) << " " 
    << parts.get(Day).getValue(d) << std::endl;
  return 0;
}

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

To be honest I don’t understand why you need this whole machinery when a simple int getPart(DatePart,Date) would suffice. Most of the inefficiencies in the code seem to be selfmade. Anyhow, to adress only the mapping from enum to something else at compile time, you can use a template and specialize it for the enum values (I left out all the other stuff, because I dont understand it, but you can add it back, the solution applies the same):

#include <iostream>

struct Date{
    int year;
    int month;
    int day;
};

enum DatePart{
    Year,
    Month,
    Day
};

template <DatePart DP>
int getPart(const Date&);

template <> int getPart<Year>(const Date& d){ return d.year;}
template <> int getPart<Month>(const Date& d){ return d.month;}
template <> int getPart<Day>(const Date& d){ return d.day;}

int main() {
  Date d({2016, 7, 23});
  std::cout << "Date " 
    << getPart<Year>(d) << " " 
    << getPart<Month>(d) << " " 
    << getPart<Day>(d) << std::endl;
}

Live Demo

As mentioned above, if you really need the Part stuff, the solution applies as well. Instead of specializing a template to return different members based on the enum value you can specialize it to return different derived instances of some base class (it could even be different return types, you don’t need runtime polymorphism when you want to choose the "part" at compile time anyhow).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading