【问题标题】:Is there a cleaner way to replicate an unordered_map with multi-type values in c++(11)是否有一种更简洁的方法可以在 c++(11) 中复制具有多类型值的 unordered_map
【发布时间】:2013-11-20 02:30:33
【问题描述】:

基本思想是得到一个存储不同类型值的unordered_map。我要做的是为 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 类中,我重载了 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];
    }
};

我正在使用 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 * 的多类型映射?

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

【问题讨论】:

  • 您是否考虑过拥有类型的多态层次结构,存储(智能)指向基类的指针?然后,您可以通过在每个元素上调用 clone() 方法来“复制”(复制)地图。或者,您可以考虑 boost 变体或 boost any。
  • @TonyD 感谢您的建议。它引导我找到这个链接:two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf
  • 与您的问题无关:您的 operator [] 的 const 版本根本不是 const 。这没有意义。
  • @c.r.看起来像是尝试使用失败的非 const 版本。
  • @C.R.你说的对。那是复制粘贴错误。谢谢。

标签: c++ types unordered-map


【解决方案1】:

boost::variantboost::any

如果您不能或不会使用 boost,请阅读他们的做法。

我自己会选择variant

【讨论】:

  • 是的,从上面 TonyD 的评论中,我正在研究这两个结构。我还发现了另一个与该主题相关的链接,其中包含一个有趣的花絮stackoverflow.com/a/6044720/1670072
【解决方案2】:

绝对是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&lt;float&gt; 等,您可能需要某种类型的代理来处理初始化列表。

【讨论】:

  • 谢谢。我会更多地研究提升变体。 boost::variant 可以接受两个以上的模板参数吗?
  • @SethHays:是的,最多 20 个。
猜你喜欢
  • 1970-01-01
  • 2014-07-05
  • 2023-03-21
  • 1970-01-01
  • 2020-10-15
  • 2012-02-16
  • 2011-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多