使用C ++,我试图创建一个通用的容器类来处理多种数据类型。这是各种解决方案的常见问题,但我发现没有任何直觉,因为我已经习惯于使用像Python或甚至VB / VBA这样的语言...
所以这是我的情景:
我已经构建了一个基于boost :: any的DataContainer类,我用它来存储多个元素的多种数据类型。我使用声明为:
的地图std::map<std::string, DataContainer* (or DataContainerBase*)>
其中DataContainer是一个封装类型为
的对象的类std::list<boost::any>
以及管理/访问列表的便利功能。
但是,最后,我仍然被迫在数据容器外进行类型转换。
例如,如果我要在地图中存储一个int值列表,那么访问它们需要:
int value = boost::any_cast<int>(map["myValue"]->get());
我宁愿将boost代码完全包含在数据容器结构中,所以我只需要输入:
int value = map["myValue"]->get();
或者,最糟糕的情况:
int value = map["myValue"]->get<int>();
当然,我可以枚举我的数据类型并执行以下操作:
int value = map["myValue"]->get( TYPE_INT );
或编写特定于类型的get()函数:
getInt(), getString(), getBool() ...
最后两个选项的问题是它们有些不灵活,要求我明确声明我希望存储在容器中的每个类型。 any_cast解决方案(我已经实现和工作)我认为很好,它只是......不优雅?我不知道。我似乎也不需要在外部使用内部机制。
在我看来,传递值而不在DataContainer成员函数的调用中声明值类型将需要一个void *解决方案(由于显而易见的原因这是不可取的),并使用&#34; get()& #34;呼叫将需要(据我所知)一个&#34;虚拟模板&#34;在基类级别定义的成员函数,当然,这是不允许的。
实际上,我有一个可行的解决方案,实际上,我在这种情况下的使用范围有限,大多数解决方案都能正常运行。但我想知道是否有更灵活的方式来管理通用的多类型数据容器。
答案 0 :(得分:6)
如果你想为此引入一些糖:
int value = boost::any_cast<int>(map["myValue"]->get());
然后你可能想让get()
函数返回一个代理对象,定义为+ - 像这样:
struct Proxy {
boost::any& value;
Proxy(boost::any& value) : value(value) {}
template<typename T>
operator T() {
return boost::any_cast<T>(value);
}
};
然后这个语法就可以了:
int value = map["myValue"]->get();
// returns a proxy which gets converted by any_cast<int>
但是我建议保持明确并且只使用该语法:
int value = map["myValue"]->get<int>();
此处get
不会返回带有模板方法的代理对象,但它本身就是模板方法(但与上面显示的模板转换运算符相同)。
答案 1 :(得分:1)
今天我已经为你想要的目的做了一些源代码。我知道这个问题太旧了,但也许这段代码对某人有帮助。它主要基于boost:any。
/*
* AnyValueMap.hpp
*
* Created on: Jun 3, 2013
* Author: alvaro
*/
#ifndef ANYVALUEMAP_HPP_
#define ANYVALUEMAP_HPP_
#include <map>
#include <boost/any.hpp>
using namespace std;
template <class T>
class AnyValueMap {
public:
AnyValueMap(){}
virtual ~AnyValueMap(){}
private:
map<T, boost::any> container_;
typedef typename map<T, boost::any>::iterator map_iterator;
typedef typename map<T, boost::any>::const_iterator map_const_iterator;
public:
bool containsKey(const T key) const
{
return container_.find(key) != container_.end();
}
bool remove(const T key)
{
map_iterator it = container_.find(key);
if(it != container_.end())
{
container_.erase(it);
return true;
}
return false;
}
template <class V>
V getValue(const T key, const V defaultValue) const
{
map_const_iterator it = container_.find(key);
if(it != container_.end())
{
return boost::any_cast<V>(it->second);
}
return defaultValue;
}
template <class V>
V getValue(const T key) const
{
return boost::any_cast<V>(container_.at(key));
}
template <class V>
void setValue(const T key, const V value)
{
container_[key] = value;
}
};
#endif /* ANYVALUEMAP_HPP_ */
一个简单的用法示例:
AnyValueMap<unsigned long> myMap;
myMap.setValue<double>(365, 1254.33);
myMap.setValue<int>(366, 55);
double storedDoubleValue = myMap.getValue<double>(365);
int storedIntValue = myMap.getValue<int>(366);