有没有一种更干净的方法可以在c++(11)中复制具有多类型值的无序映射

Is there a cleaner way to replicate an unordered_map with multi-type values in c++(11)

本文关键字:复制 多类型 映射 无序 c++ 一种 有没有 方法      更新时间:2023-10-16

基本思想是获得一个存储不同类型值的无序映射。我想做的是创建一个易于访问的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::数组类型。还请注意,我正在使用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*的多类型映射?

注意:我在Windows上使用VS2013,在Mac和Linux上使用clang。

boost::variantboost::any

如果你不能或不想使用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 };
}

如果您想要在不键入std::vector<float>等的情况下使用{ 0.1f, 0.1f, 0.0f }语法,则可能需要某种类型的代理来处理初始值设定项列表。