2013-11-20 1 views
0

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

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; 

В моем классе УБО я перегружен оператор []:

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

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

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

+0

Вы считали наличие полиморфной иерархии типов, сохраняющих (умные) указатели на базовый класс? Затем вы можете «реплицировать» (скопировать) карту, вызвав метод 'clone()' для каждого элемента. В качестве альтернативы, вы можете рассмотреть вариант повышения или увеличить любой. –

+0

@TonyD Спасибо за предложение. Мне удалось найти эту ссылку: http://www.two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf –

+1

Не связанный с вашим вопросом: ваша версия const 'operator []' не const at все. Это не имеет смысла. –

ответ

0

Определенно boost::variant. Это то, для чего он создан. Вот small example с помощью кода:

#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

Спасибо. Я рассмотрю более мощный вариант. Может ли форматировать :: variant принимать более двух шаблонных параметров? –

+0

@SethHays: Да, до 20. –

2

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

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

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

+0

Да, из комментария TonyD выше я изучал эти две структуры. Я также нашел еще одну ссылку, которая связывает эту тему с интересным лакомым куском http://stackoverflow.com/a/6044720/1670072 –