是否有一种更简洁的方法可以在 c++(11) 中复制具有多类型值的 unordered_map
Posted
技术标签:
【中文标题】是否有一种更简洁的方法可以在 c++(11) 中复制具有多类型值的 unordered_map【英文标题】:Is there a cleaner way to replicate an unordered_map with multi-type values in c++(11) 【发布时间】: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.你说的对。那是复制粘贴错误。谢谢。
【参考方案1】:
boost::variant
或 boost::any
。
如果您不能或不会使用 boost,请阅读他们的做法。
我自己会选择variant
。
【讨论】:
是的,从上面 TonyD 的评论中,我正在研究这两个结构。我还发现了另一个与该主题相关的链接,其中包含一个有趣的花絮***.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<float>
等,您可能需要某种类型的代理来处理初始化列表。
【讨论】:
谢谢。我会更多地研究提升变体。 boost::variant 可以接受两个以上的模板参数吗? @SethHays:是的,最多 20 个。以上是关于是否有一种更简洁的方法可以在 c++(11) 中复制具有多类型值的 unordered_map的主要内容,如果未能解决你的问题,请参考以下文章
是否有一种简洁的方法可以为同一个扩展定义两个或多个 bash 别名?