2013-05-01 5 views
1

У меня есть требование о внедрении C++ класса для поддержки следующихРеализовать C++, который поддерживает 2 уровень выглядит с ключами любого типа

данные:

ключа - строка

подключи - строка/двойная

Значение - строка/двойной

ключ & подключ вместе идентифицирует строку однозначно.

Eg:

[ "key", "subkey", "value" ] 

[ "cse", "a", 100 ] 

[ "cse", "b", 120 ] 

[ "cse", 100, 10 ] 

Операция:

1) Учитывая ключевым & возвращаемого значения

2) Учитывая ключ возврата массива [ "subkey", "value" ]

Проблемы Я облицовка - это то, что подраздел и значение могут быть как двойными, так и строковыми. Один из способов решения этой проблемы - наличие класса-оболочки, который имеет возможность хранить как двойные, так и строковые типы.

Карта первого уровня будет содержать строку в качестве ключа, а значение будет представлять собой карту.

Карта второго уровня будет иметь ключ, так как новый класс-оболочка и значение также являются новым классом-оболочкой.

Этот подход подходит? или есть ли лучшие способы сделать это?

ответ

2

Я взломал решение, используя Boost.Variant и C++ 11 unordered_map. Код является довольно приятным примером для C++ 11 в действии.

Вы должны обратить особое внимание на сочетание двух хэшей в специализации std::hash<key>::operator(), он может иметь сильное влияние на качество хеширования. Для лучшей реализации взгляните на boost::hash_combine, который, к сожалению, не был стандартизован.

В общем то, что код делает: определить специальный тип ключа, который EqualityComparable и Hashable, а затем использовать его в std::unordered_map. Вы можете построить все это только с помощью Boost и без C++ 11. Если у вас нет Boost или C++ 11, вы находитесь в плотном месте. На этом не было проведено никаких реальных испытаний.

#include <boost/variant.hpp> 
#include <string> 
#include <functional> 
#include <unordered_map> 
#include <iostream> 

struct key { 
    std::string primary; 
    boost::variant<std::string, double> secondary; 
    friend bool operator==(const key& x, const key& y) 
    { return x.primary == y.primary && x.secondary == y.secondary; } 
}; 

namespace std { 
template<> 
struct hash<key> { 
    std::size_t operator()(const key& k) const 
    { 
    std::size_t first = std::hash<std::string>()(k.primary); 
    std::size_t second; 

    // check for the more likely case first 
    if(const std::string* s = boost::get<std::string>(&(k.secondary))) { 
     second = std::hash<std::string>()(*s); 
    } else { 
     const double* d = boost::get<double>(&(k.secondary)); 
     second = std::hash<double>()(*d); 
    } 
    return first^(second << 1); // not so fancy hash_combine 
    } 
}; 

} // std 


int main() 
{ 
    typedef std::unordered_map<key, boost::variant<std::string, double>> MyMap; 
    MyMap m = { 
    {{"foo", "bar"}, "foobar"}, 
    {{"foo", 23.0}, "foo23"}, 
    {{"nothing", 23.0}, 23.0} 
    }; 

    std::cout << m[{"foo", "bar"}] << std::endl; 
    std::cout << m[{"foo", 23.0}] << std::endl; 
    std::cout << m[{"nothing", 23.0}] << std::endl; 

    return 0; 
} 
1

следующие отходы немного пространства для каждого ключа, но имеет преимущество в простоте:

struct Key 
{ 
    Key(string primary, string subkey) 
     : primary(primary) 
     , is_double(false) 
     , string_subkey(subkey) 
    {} 

    Key(string primary, double subkey) 
     : primary(primary) 
     , is_double(true) 
     , double_subkey(subkey) 
    {} 

    string primary; 
    bool is_double; 
    double double_subkey; 
    string string_subkey; 
}  

Вы должны осуществлять соответствующие операции сравнения и/или хэш-функцию.

+0

Довольно пустая трата пространства, но, вероятно, она будет работать в большинстве ситуаций. Рассмотрите союзы или абстрагирование более высокого уровня. – pmr

+0

@pmr: Да, я не мог потрудиться, глядя на синтаксис синтаксиса C++ 11 non-POD. –