Есть ли более чистый способ репликации unordered_map с многотипными значениями в c ++ (11)

0

Основная идея - получить unordered_map, который хранит значения разных типов. То, что я пытаюсь сделать, - создать легкодоступный объект для Uniform Buffer Object OpenGL. Конечный продукт будет выглядеть примерно так:

UBO ubo = { "Uniforms", "translation", "scale", "rotation", "enabled" };
ubo["scale"]       = 0.5f;
ubo["translation"] = { 0.1f, 0.1f, 0.0f };
ubo["rotation"]    = { 90.0f, 0.0f, 0.0f, 1.0f };
ubo["enabled"]     = GL_TRUE; 

В моем классе UBO я перегрузил оператора []:

struct UBOData;

class UBO
{
    std::unordered_map<std::string,UBOData>
    ...
    public: 
    UBOData &operator[](std::string key)
    {
        UBOData data = new UBOData();
        dataMap.emplace(key, data);
        return data;
    }

    const UBOData& operator[](std::string key)
    {
        return const_cast<UBOData&>(*this)[key];
    }
};

И я использую UBOData для хранения разных типов данных. Именно здесь мое доверие ослабевает в свете того, что "правильно" в мире c++.

.
.
.
struct UBOData
{
    enum ReturnType {Undefined, rInt, rFloat, rDouble};

    void       *value;
    ReturnType type;
    int &operator=(int lhs);
    float &operator=(float lhs);
    double &operator=(double lhs);
};

Я усекал типы для этого примера, без типов std :: array. Также обратите внимание, что я использую void * для хранения значения и говорю мне, что мне нужно переосмыслить мой дизайн. Конечно, я так понимаю, почему я здесь :)

int &UBOData::operator=(int lhs)
{
    if (type == Undefined) { type = rInt; } else { assert(type == rInt); }
    value = new int(lhs);
    int &rValue = *((int*)value);
    return rValue;
}

float &UBOData::operator=(float lhs)
{
    if (type == Undefined) { type = rFloat; }
    else { assert(type == rFloat); }

    value = new float(lhs);
    float &rValue = *((float*)value);
    return rValue;
}

double &UBOData::operator=(double lhs)
{
    if (type == Undefined) { type = rDouble; }
    else { assert(type == rInt); }

    value = new double(lhs);
    double &rValue = *((double*)value);
    return rValue;
}

Я попытался обернуть void * с проверкой типа, но есть ли лучший способ получить многотипную карту без void *?

Примечание. Я использую VS2013 для Windows и звоню на Mac и Linux.

  • 0
    Рассматривали ли вы наличие полиморфной иерархии типов, хранящих (умные) указатели на базовый класс? Затем вы можете «реплицировать» (копировать) карту, вызывая метод clone() для каждого элемента. В качестве альтернативы, вы можете рассмотреть вариант повышения или повышения любой.
  • 0
    @TonyD Спасибо за предложение. Это привело меня к поиску этой ссылки: two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf
Показать ещё 3 комментария
Теги:
types
unordered-map

2 ответа

0
Лучший ответ

Определенно boost :: variant. Это то, для чего он создан. Вот небольшой пример использования вашего кода:

#include <unordered_map>
#include <vector>
#include <boost/variant.hpp>

class UBO
{
    using UBOData = boost::variant<float, std::vector<float>>;
    std::unordered_map<std::string, UBOData> dataMap;
    public: 
    UBO() : dataMap(){}
    UBOData &operator[](const std::string& key)
    {
        return dataMap[key];
    }
};

int main()
{
   UBO ubo;
   ubo["scale"]       = 0.5f;
   ubo["translation"] = std::vector<float>{ 0.1f, 0.1f, 0.0f };
   ubo["rotation"]    = std::vector<float>{ 90.0f, 0.0f, 0.0f, 1.0f };
}

Если вам нужен { 0.1f, 0.1f, 0.0f } без ввода std::vector<float> и т.д., Вам, вероятно, понадобится некоторый тип прокси-сервера, который обрабатывает списки инициализаторов.

  • 0
    Благодарю. Я буду смотреть на вариант повышения больше. Может ли boost :: option принимать более двух параметров шаблона?
  • 0
    @SethHays: Да, до 20.
2

boost::variant или boost::any.

Если вы не можете или не будете использовать boost, прочитайте, что они сделали.

Я бы пошел с variant сам.

  • 0
    Да, из комментария TonyD выше, я изучал эти две структуры. Я также нашел другую ссылку, которая связана с этой темой с интересным tidbit stackoverflow.com/a/6044720/1670072

Ещё вопросы

Сообщество Overcoder
Наверх
Меню