0

The basic idea is to get a unordered_map that stores values of different types. What I am trying to do is to create an easy accessible object to a OpenGL Uniform Buffer Object. The end product would look something like:

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; 

In my UBO class I have overloaded operator[]:

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

And I am using UBOData to store different data types. This is where my confidence wanes in the light of what is "right" in the c++ world.

. . . struct UBOData { enum ReturnType {Undefined, rInt, rFloat, rDouble}; void *value; ReturnType type; int &operator=(int lhs); float &operator=(float lhs); double &operator=(double lhs); }; 

I have truncated the types for this example, no std::array types. Also notice I am using a void * to store the value and tell me I need to rethink my design. Of course I do that's why I am here :)

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

I've attempted to wrap the void* with type checking but is there a better way to get a multi-type map without void *?

Note: I am using VS2013 on Windows and clang on Mac and Linux.

5
  • Have you considered having a polymorphic hierarchy of types, storing (smart) pointers to the base class? You can then "replicate" (copy) the map by having it invoke a clone() method on each element. Alternatively, you might consider boost variant or boost any. Commented Nov 20, 2013 at 2:41
  • @TonyD Thanks for the suggestion. It lead me to find this link: two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf Commented Nov 20, 2013 at 3:18
  • 1
    Unrelated to your question: your const version of operator [] is not const at all. It doesn't make sense. Commented Nov 20, 2013 at 3:21
  • @c.r. looks like an attempt to use the non const version that failed miserably. Commented Nov 20, 2013 at 3:37
  • @C.R. You are right. That is a copy paste error. Thanks. Commented Nov 20, 2013 at 3:42

2 Answers 2

2

boost::variant or boost::any.

If you cannot or will not use boost, read what they did.

I would go with variant myself.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes from TonyD's comment above I was looking into those two structure. I also found another link that ties into this topic with an interesting tidbit stackoverflow.com/a/6044720/1670072
0

Definitely boost::variant. That is what its built for. Here is a small example using your code:

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

If you want the { 0.1f, 0.1f, 0.0f } syntax without typing std::vector<float>, etc, you probably would need some type of proxy that handles initializer lists.

2 Comments

Thanks. I will look into boost variant more. Can boost::variant take more than two template params?
@SethHays: Yes, up to 20.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.