2013-03-08 94 views
0

我想做一个模板类作为占位符类,它可以容纳类似的东​​西,字符串和类型的T对象。下面是我写的相同的代码。C++使模板类作为另一个类中的占位符

#include <iostream> 
#include <string> 
#include <map> 

using namespace std; 

//A class which act as placeholder to hold 
//unknown object. Something similar as Object 
//in Java 
template <typename T> 
class Genric 
{ 
    public: 
     map<string, T> addP; //This will be placeholder for time 
     // being. 
}; 

class A 
{ 
    public: 
     Genric t1; //Have object of Genric class so that we can 
     // access the member variable in future. 
     void foo() 
     { 
      cout<<"Calling foo"<<endl; 
     } 
}; 

int main() 
{ 
    A a1; 
    a1.foo(); 
} 

但是,当我试图编译我得到以下错误。

$ g++ tempClass.cxx 
tempClass.cxx:21:9: error: invalid use of template-name 'Genric' without an argument list 

上面Genric类的目的只是充当将来可以填充的其中一个成员变量的占位符类。 那么有没有一种方法可以写出这样的Genric类。

回答

2

你需要的东西像boost::any

map<string, boost::any> anywayzz; 

您可以将任何对象存储在它。您不需要Genric类模板。

如果你不使用boost,那么你可以自己实现any。寻找其实施,或类型擦除,在这个网站上。你一定会有一些想法。从这里开始:

2

您正在定义Genric为模板类,但随后试图初始化t1没有给人一种类型吧。那是你得到的错误。尝试例如:

Genric<int> t1; 

或者,如果你正在寻找一个真正运行时一般,看看的boost ::任何

2

在编译程序之前,模板是“通用”的。此时,必须让编译器知道它需要处理哪些类型。

如果您希望某个可以包含编译时未知(更好:尚未知道)类型模板的东西不是解决方案。由于实际类型只是在运行时才知道,所以你必须转向最终包装在“处理程序”中的基于运行时的多态(继承自多态基)。

从本质上讲,您需要一个基本的函数,它允许您检查类型以及实现该函数的泛型派生类,以适合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相关的包装函数映射表。 对于需要序列化/反序列化的所有类型,此表必须进行预初始化。

但这样的长走你原来的问题,不谈论序列化/反序列化。

如果问题是“系列化”,在“类型擦除”不是一个完整的解决方案。你应该更多地关注“工厂模式”。并发布更适合该论点的另一个问题。

+0

看来这可以工作,但有这样的占位符类的最终目标是,使用S11N ::反序列化,可以在运行时,但如果未知的东西来,然后如何照顾与做一个基本类型反序列化反序列化对象以上方法。 – Abhinav 2013-03-08 09:56:06

+0

@Abhinav:看到编辑。 – 2013-03-08 11:18:12

相关问题