将枚举映射到 const 类 的最佳设计
the best design for mapping enums to const classes
我有这个有效的例子:
我为枚举的每个值创建一个实现“PartInterface”的对象,并将它们添加到映射中。但我觉得这并不令人满意,因为一切都可以在编译时而非运行时推断出来。
在 C++ 11 中有更优雅的方法吗?
另一种解决方案是在每次调用“get”函数时构建“YearPart”、“MonthPart”和“DayPart”对象,
但在我看来效率较低...
#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;
}
老实说,我不明白为什么一个简单的 int getPart(DatePart,Date)
就足够了,为什么您需要整台机器。代码中的大部分低效似乎都是自制的。无论如何,要在编译时仅处理从枚举到其他东西的映射,您可以使用模板并将其专门用于枚举值(我省略了所有其他内容,因为我不明白,但您可以将其添加回去,解决方案同样适用):
#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;
}
如上所述,如果您确实需要 Part
东西,该解决方案也适用。您可以根据枚举值将模板专门化为 return 不同的成员,而不是将其专门化为 return 某些基础 class 的不同派生实例(它甚至可以是不同的 return类型,当您想在编译时选择“部分”时,您不需要运行时多态性)。
我有这个有效的例子: 我为枚举的每个值创建一个实现“PartInterface”的对象,并将它们添加到映射中。但我觉得这并不令人满意,因为一切都可以在编译时而非运行时推断出来。 在 C++ 11 中有更优雅的方法吗? 另一种解决方案是在每次调用“get”函数时构建“YearPart”、“MonthPart”和“DayPart”对象, 但在我看来效率较低...
#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;
}
老实说,我不明白为什么一个简单的 int getPart(DatePart,Date)
就足够了,为什么您需要整台机器。代码中的大部分低效似乎都是自制的。无论如何,要在编译时仅处理从枚举到其他东西的映射,您可以使用模板并将其专门用于枚举值(我省略了所有其他内容,因为我不明白,但您可以将其添加回去,解决方案同样适用):
#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;
}
如上所述,如果您确实需要 Part
东西,该解决方案也适用。您可以根据枚举值将模板专门化为 return 不同的成员,而不是将其专门化为 return 某些基础 class 的不同派生实例(它甚至可以是不同的 return类型,当您想在编译时选择“部分”时,您不需要运行时多态性)。