我想实现一个可以存储任何数据类型(如boost :: any)的变量类,但需要支持数据类型转换。例如,
Variant v1(int(23)); can be converted to bool via v1.get<bool>()
using Conv<int, bool>, Variant v2(CustomT1()); to CustomT2
via Conv<CustomT1, CustomT2> and so on.
这是当前的实现,基于boost :: any:
的想法#include <iostream>
#include <string>
#include <memory>
#include <stdexcept>
template<typename Src, typename Dest>
struct Conv
{
/* static? */ Dest convert(const Src& src) const { throw std::runtime_error("type cast not supported"); }
};
template<> struct Conv<int, bool>
{
bool convert(const int &src) const { return src > 0; }
};
class IStoredVariant
{};
template<typename T>
struct variant_storage : public IStoredVariant
{
variant_storage(const T& value) : m_value(value)
{}
T& getValue(void) { return this->m_value; }
const T& getValue(void) const { return this->m_value; }
template<typename U>
U make_conversion(void) const // just an idea...
{
return Conv<U, T>().convert(this->getValue());
}
protected:
T m_value;
};
class Variant
{
public:
template<typename T>
Variant(const T& value) : m_storage(new variant_storage<T>(value))
{}
IStoredVariant& getImpl(void) { return *this->m_storage; }
const IStoredVariant& getImpl(void) const { return *this->m_storage; }
std::auto_ptr<IStoredVariant> m_storage;
template<typename T>
T get(void) const
{
const IStoredVariant &var = this->getImpl();
// ????????????
// How to perform conversion?
}
template<typename T>
void set(const T &value)
{
this->m_storage.reset(new variant_storage<T>(value));
}
};
int main(void)
{
Variant v(int(23));
bool i = v.get<bool>();
}
来自get&lt;&gt;模板方法,我只能访问IStoredVariant指针,但我需要知道具体的类型来选择转换器&lt;&gt;。是否有任何设计模式或解决方法来解决这个问题?
答案 0 :(得分:2)
这是不可能的。您需要支持虚拟功能中的模板才能实现这一点。
在调用上下文中,您只有要转换的类型,并且无法检索存储的类型。在调用上下文中,您只有存储的类型,无法检索要转换的类型。
无法在它们之间传递类型,因此您永远不会同时知道这两种类型,因此无法执行任何转换。
答案 1 :(得分:1)
你的问题很棘手。
如果你丢失了类型信息,那么就无法恢复它(不完全),因为语言本身不支持它(没有反思/内省)。
您仍然可以知道确切的类型,但是无法获得诸如转换为任意类型之类的属性,因为转换机制在编译时被烘焙(取决于构造函数,转换运算符和语言规则)。
如果您只有一小部分您感兴趣的类型,那么Boost.Variant
是您最好的选择。
如果你真的想拥有一个完全动态的语言......那么要么放弃C ++,要么在C ++之上重新实现动态语言......
答案 2 :(得分:0)
您可以使用typeid
运算符获取变体中存储的类型的类型信息,并将其与typeid
中T
的{{1}}进行比较:< / p>
使用此接口定义扩展get
:
IStoredVariant
将实施添加到具体变体存储:
class IStoredVariant
{
...
type_info getTypeId() = 0; // note the abstract definition
...
}
在Variant类中使用它:
template<typename T>
struct variant_storage : public IStoredVariant
{
...
type_info getTypeId() { return typeid(T); }
...
}
编辑:您还可以查看不使用class Variant
{
...
template<typename T>
T get(void) const
{
const IStoredVariant *var = this->getImpl();
if(typeid(T) == var->getTypeId())
{
// type matches: cast to the type
variant_storage<T>* my_typed_var = static_cast<variant_storage<T>* >(var);
// do something with it
}
}
}
的{{3}},但查看特定类型的枚举。因此,不支持所有其他类型。