枚举类的哈希表的正确放置

时间:2019-03-14 05:00:59

标签: c++ c++11 boost enum-class

我正在从事一个高级项目,并且对如何最好地为我的程序实现查找表有疑问。有几个enum class文件包含enum class和一个operator<<重载以将它们输出到std::string。我们正在使用boost属性树来解析JSON文件,并且默认情况下,解析无法将字符串转换为enum class。由于我们在程序中的某些时候需要枚举类和字符串,因此实现std::unordered_map是有意义的。但是,我的问题是如何根据文件放置查找表?

当前,我们的代码有4个枚举类文件,总结如下:

namespace wiregen{
    enum class {/* values */}
    ostream& operator<<(ostream& os, enum){/*overload code to output enum as a string*/}
}

枚举需要公开,因为它们被多个类使用。我目前已定义它们,并且在枚举头文件中定义了operator <<重载。我的问题是,是否应该将查找表放在enum标头中,进行枚举实现,然后将查找表移到其中,还是其他?

2 个答案:

答案 0 :(得分:1)

尽管这只是一个基于设计的问题,但我建议您将地图放置在匿名名称空间中,以便从界面中隐藏它。此方法不需要其他实现文件,因为您可以从括号列表中初始化常量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;          
}                                                                       

答案 1 :(得分:0)

作为解决此问题的方法,我发现最好的解决方法是将枚举包装在一个类中,然后将函数作为该类的一部分提供给我想要的功能。我不得不将它们从范围枚举更改为普通枚举,但现在它提供了我们所需的行为。

下面是一个示例

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;
    }
}