在编译程序之前,模板是“通用”的。此时,必须让编译器知道它需要处理哪些类型。
如果您希望某个可以包含编译时未知(更好:尚未知道)类型模板的东西不是解决方案。由于实际类型只是在运行时才知道,所以你必须转向最终包装在“处理程序”中的基于运行时的多态(继承自多态基)。
从本质上讲,您需要一个基本的函数,它允许您检查类型以及实现该函数的泛型派生类,以适合all
类型的方式。
boost :: any可以是一个实现,但可以有更简单的方法,特别是考虑到“允许发现运行时类型的函数”不超过... dynamic_cast
。
可以使COMETO这样
#include <memory>
class any_value
{
template<class T>
class wrapper; //see below
class common_base
{
public:
virtual ~common_base() {} //this makes the type polymorphic
template<class T>
T* has_value()
{
auto* ptr = dynamic_cast<wrapper<T>*>(this);
return ptr? &ptr->m: nullptr;
}
};
template<class T>
class wrapper: public common_base
{
public:
wrapper() :m() {}
wrapper(const T& t) :m(t) {}
T m;
};
std::unique_ptr<common_base> pb;
public:
any_value() {}
template<class T>
any_value(const T& t) :pb(new wrapper<T>(t)) {}
template<class T>
any_value& operator=(const T& t)
{ pb = std::unique_ptr<common_base>(new wrapper<T>(t)); return *this; }
any_value(any_value&&) =default;
any_value& operator=(any_value&&) =default;
//NOW THE GETTERS
template<class T>
T* get() const //nullptr if not holding a T*
{ return bool(pb)? pb->has_value<T>(): nullptr; }
template<class T>
bool get(T& t)
{
T* pt = get<T>();
if(pt) t = *pt;
return bool(pt);
}
};
#include <iostream>
#include <string>
int main()
{
any_value a(5), b(2.7192818), c(std::string("as a string"));
int vi=0; double vd=0; std::string vs;
if(!a.get(vi)) vi=0; //will go
if(!a.get(vd)) vd=0; //will fail
if(!a.get(vs)) vs.clear(); //will fail
std::cout <<"vi = "<<vi<<", vd = "<<vd<<", vs = "<<vs<<" \n";
if(!b.get(vi)) vi=0; //will fail
if(!b.get(vd)) vd=0; //will go
if(!b.get(vs)) vs.clear(); //will fail
std::cout <<"vi = "<<vi<<", vd = "<<vd<<", vs = "<<vs<<" \n";
if(!c.get(vi)) vi=0; //will fail
if(!c.get(vd)) vd=0; //will fail
if(!c.get(vs)) vs.clear(); //will go
std::cout <<"vi = "<<vi<<", vd = "<<vd<<", vs = "<<vs<<" \n";
}
解决以下阿比纳夫评论:
由于C++类型系统是静态的,你不能-in中普通反序列化一个“未知“,除非您首先反序列化可以是”已知“的内容。为此,首先需要一种将C++类型(不是对象)表示为可识别值(类型uid)的方法,以及创建用于这些“值”的包装器的“工厂”。
保存时,您只需保存即 uid,然后通过common_base虚函数询问是否保存包装的值。 在装载时,首先加载UID,比创建具有适当类型一个新的包装(见后),比通过common_base虚函数加载值。
要建立一个适当的包装,你需要的UID-S实现这一创建类型UID相关的包装函数映射表。 对于需要序列化/反序列化的所有类型,此表必须进行预初始化。
但这样的长走你原来的问题,不谈论序列化/反序列化。
如果问题是“系列化”,在“类型擦除”不是一个完整的解决方案。你应该更多地关注“工厂模式”。并发布更适合该论点的另一个问题。
看来这可以工作,但有这样的占位符类的最终目标是,使用S11N ::反序列化,可以在运行时,但如果未知的东西来,然后如何照顾与做一个基本类型反序列化反序列化对象以上方法。 – Abhinav 2013-03-08 09:56:06
@Abhinav:看到编辑。 – 2013-03-08 11:18:12