правильное размещение хеш-таблицы для класса enum - PullRequest
0 голосов
/ 14 марта 2019

Я работаю над старшим проектом и задаю вопрос о том, как наилучшим образом реализовать справочную таблицу для моей программы.Существует несколько файлов enum class, которые содержат enum class es и перегружены operator<<, чтобы вывести их на std::string s.Мы используем дерево свойств boost для анализа файла JSON, и анализ не может преобразовать строку в enum class по умолчанию.Поскольку в какой-то момент программы нам нужны как классы enum, так и строки, имеет смысл реализовать std::unordered_map.Моя проблема, однако, заключается в том, где мне разместить таблицу поиска в терминах моих файлов?

В настоящее время наш код содержит 4 файла классов enum, которые в сумме имеют вид

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

Перечисления должны быть общедоступными какони используются несколькими классами.В настоящее время они определены, а оператор << перегружен определен в заголовочных файлах enum.Мой вопрос, однако, должен ли я поместить таблицу поиска в заголовок enum, сделать реализацию enum и переместить таблицу поиска туда, или что-то еще? </p>

Ответы [ 2 ]

1 голос
/ 14 марта 2019

Хотя это немного вопрос, основанный на дизайне, я бы рекомендовал поместить карту в анонимное пространство имен, чтобы скрыть ее от интерфейса. Этот подход не требует дополнительного файла реализации, так как вы можете инициализировать константу 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;          
}                                                                       
0 голосов
/ 18 марта 2019

В качестве решения этой проблемы я обнаружил, что наилучшее решение заключалось в том, чтобы обернуть перечисления в классе, а затем создать функции как часть этого класса, чтобы получить требуемую функциональность.Мне пришлось поменять их с перечислений с областью видимости на обычные, но теперь он обеспечивает необходимое нам поведение.

Пример приведен ниже

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