正确放置枚举 class 的散列 table
proper placement of a hash table for enum class
我正在从事一个高级项目,并且有一个关于如何最好地为我的程序实现查找 table 的问题。有几个 enum class
文件包含 enum class
es 和一个 operator<<
重载以将它们输出到 std::string
s。我们正在使用 boost 属性 树来解析 JSON 文件,默认情况下解析无法将字符串转换为 enum class
。由于我们在程序中的某个时刻同时需要枚举 classes 和字符串,因此实现 std::unordered_map
是有意义的。不过,我的问题是根据我的文件将查找 table 放在哪里?
目前我们的代码有 4 个枚举 class 个文件,总结为
namespace wiregen{
enum class {/* values */}
ostream& operator<<(ostream& os, enum){/*overload code to output enum as a string*/}
}
枚举需要 public,因为它们被多个 class 使用。我目前已经定义了它们,并且在枚举 header 文件中定义了 operator<< 重载。不过,我的问题是我应该将查找 table 放在枚举 header 中,进行枚举实现并将查找 table 移到那里,还是其他?
虽然这是一个基于设计的问题,但我建议将地图放在匿名命名空间中,以便在界面中隐藏它。这种方法不需要额外的实现文件,因为您可以从花括号列表初始化常量 unordered_map
。
// SomeHeader.h
enum class Color {
Red,
Blue,
Green,
Unknown,
};
// Anonymous namespace to hide our implementation
namespace {
std::unordered_map<std::string, Color> const stringToColorMap_ = {
{ "Red", Color::Red },
{ "Blue", Color::Blue },
{ "Green", Color::Green },
};
}
// Public interface
Color colorFromString(std::string const& s) {
auto it = stringToColorMap_.find(s);
if (it != stringToColorMap_.end()) {
return it->second;
}
return Color::Unknown;
}
int main() {
cout << static_cast<int>(colorFromString("Red")) << endl;
cout << static_cast<int>(colorFromString("Blue")) << endl;
}
作为这个问题的解决方案,我发现最好的解决方案是将枚举包装在 class 中,然后将函数作为 class 的一部分来提供我正在寻找的功能。我不得不将它们从作用域枚举更改为普通枚举,但它现在提供了我们需要的行为。
示例如下
Base.hpp
namespace wiregen{
class Base{
public:
enum baseEnum{
/*removed for brevity*/
};
Base();
constexpr Base(baseEnum b) : val(b){}
bool operator==(Base b) const;
bool operator!=(Base b) const;
operator std::string() const;
void operator = (const std::string &str);
private:
baseEnum val;
};
std::ostream& operator<<(std::ostream& os, const wiregen::Base& b);
}
Base.cpp
namespace{
typedef boost::bimap<wiregen::Base::baseEnum, std::string>BaseTable;
typedef BaseTable::value_type baseString;
BaseTable m_base = boost::assign::list_of<baseString>
/* removed for brevity */
}
namespace wiregen{
Base::Base(){val = baseEnum::invalid;}
bool Base::operator==(Base b) const{return val == b.val;}
bool Base::operator!=(Base b) const{return val != b.val;}
Base::operator std::string() const{
auto it = m_base.left.find(val);
if(it != m_base.left.end()){
return it->second;
}
return "invalid";
}
void Base::operator = (const std::string &str){
auto it = m_base.right.find(boost::algorithm::to_lower_copy(str));
if(it != m_base.right.end()){
val = it->second;
return;
}
std::cerr<<"Failed to assign Base: "<<str<<std::endl;
return;
}
std::ostream& operator<<(std::ostream& os, const Base& b){
os << (std::string)b;
return os;
}
}
我正在从事一个高级项目,并且有一个关于如何最好地为我的程序实现查找 table 的问题。有几个 enum class
文件包含 enum class
es 和一个 operator<<
重载以将它们输出到 std::string
s。我们正在使用 boost 属性 树来解析 JSON 文件,默认情况下解析无法将字符串转换为 enum class
。由于我们在程序中的某个时刻同时需要枚举 classes 和字符串,因此实现 std::unordered_map
是有意义的。不过,我的问题是根据我的文件将查找 table 放在哪里?
目前我们的代码有 4 个枚举 class 个文件,总结为
namespace wiregen{
enum class {/* values */}
ostream& operator<<(ostream& os, enum){/*overload code to output enum as a string*/}
}
枚举需要 public,因为它们被多个 class 使用。我目前已经定义了它们,并且在枚举 header 文件中定义了 operator<< 重载。不过,我的问题是我应该将查找 table 放在枚举 header 中,进行枚举实现并将查找 table 移到那里,还是其他?
虽然这是一个基于设计的问题,但我建议将地图放在匿名命名空间中,以便在界面中隐藏它。这种方法不需要额外的实现文件,因为您可以从花括号列表初始化常量 unordered_map
。
// SomeHeader.h
enum class Color {
Red,
Blue,
Green,
Unknown,
};
// Anonymous namespace to hide our implementation
namespace {
std::unordered_map<std::string, Color> const stringToColorMap_ = {
{ "Red", Color::Red },
{ "Blue", Color::Blue },
{ "Green", Color::Green },
};
}
// Public interface
Color colorFromString(std::string const& s) {
auto it = stringToColorMap_.find(s);
if (it != stringToColorMap_.end()) {
return it->second;
}
return Color::Unknown;
}
int main() {
cout << static_cast<int>(colorFromString("Red")) << endl;
cout << static_cast<int>(colorFromString("Blue")) << endl;
}
作为这个问题的解决方案,我发现最好的解决方案是将枚举包装在 class 中,然后将函数作为 class 的一部分来提供我正在寻找的功能。我不得不将它们从作用域枚举更改为普通枚举,但它现在提供了我们需要的行为。
示例如下
Base.hpp
namespace wiregen{
class Base{
public:
enum baseEnum{
/*removed for brevity*/
};
Base();
constexpr Base(baseEnum b) : val(b){}
bool operator==(Base b) const;
bool operator!=(Base b) const;
operator std::string() const;
void operator = (const std::string &str);
private:
baseEnum val;
};
std::ostream& operator<<(std::ostream& os, const wiregen::Base& b);
}
Base.cpp
namespace{
typedef boost::bimap<wiregen::Base::baseEnum, std::string>BaseTable;
typedef BaseTable::value_type baseString;
BaseTable m_base = boost::assign::list_of<baseString>
/* removed for brevity */
}
namespace wiregen{
Base::Base(){val = baseEnum::invalid;}
bool Base::operator==(Base b) const{return val == b.val;}
bool Base::operator!=(Base b) const{return val != b.val;}
Base::operator std::string() const{
auto it = m_base.left.find(val);
if(it != m_base.left.end()){
return it->second;
}
return "invalid";
}
void Base::operator = (const std::string &str){
auto it = m_base.right.find(boost::algorithm::to_lower_copy(str));
if(it != m_base.right.end()){
val = it->second;
return;
}
std::cerr<<"Failed to assign Base: "<<str<<std::endl;
return;
}
std::ostream& operator<<(std::ostream& os, const Base& b){
os << (std::string)b;
return os;
}
}