具有自动转换支持的boost::any等变体实现
Variant implementation like boost::any with auto-conversion support
我想实现一个变体类,它可以存储任何数据类型(如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<>模板方法中,我只能访问IStoredVariant指针,但是我需要知道选择Converter<>的具体类型。是否有任何设计模式或变通方法来解决这个问题?
这不可能。要实现这一点,您需要在虚函数中支持模板。
在调用上下文中,您只有要转换为的类型,而不能检索存储的类型。在called上下文中,您只有存储的类型,而不能检索要转换为的类型。
无法在它们之间传递类型,因此您永远无法同时知道这两种类型,因此无法执行任何转换。
你的问题很棘手。
如果丢失了类型信息,则无法(不完全)恢复它,因为语言本身不支持它(没有反射/自省)。
您仍然可以知道确切的类型,但是您不能获得诸如到任意类型的转换之类的属性,因为转换机制是在编译时内置的(取决于构造函数、转换操作符和语言规则)。
如果您感兴趣的类型只有一小部分,那么Boost.Variant
是您最好的选择。
如果你真的想要一个完全动态的语言…那么要么放弃c++,要么在c++的基础上重新实现一种动态语言…
您可以使用typeid
运算符来获取存储在变体中的类型的类型信息,并将其与get
中T
的typeid
进行比较:
用这个接口定义扩展IStoredVariant
:
class IStoredVariant
{
...
type_info getTypeId() = 0; // note the abstract definition
...
}
将实现添加到具体的变量存储:
template<typename T>
struct variant_storage : public IStoredVariant
{
...
type_info getTypeId() { return typeid(T); }
...
}
在Variant类中使用:
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
}
}
}
EDIT:您还可以查看OGRE的属性实现,它不使用typeid
,而是对特定类型集使用枚举。因此,不支持所有其他类型。
相关文章:
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 为什么这种类型的擦除实现(简化的 boost:any)会出现分段错误
- 如何实现"Press Any Key To Exit"
- 使用 shared_ptrs 对<无符号 int、boost::any> 类型的通用容器的线程安全实现
- 具有自动转换支持的boost::any等变体实现