C ++将模板类作为占位符放在另一个类中

时间:2013-03-08 07:26:26

标签: c++ templates

我正在尝试将模板类设置为占位符类,它可以包含类似于字符串和类型的T对象。下面是我为此编写的代码。

#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类。

3 个答案:

答案 0 :(得分:2)

您需要boost::any之类的内容:

map<string, boost::any> anywayzz;

您可以在其中存储任何对象。您不需要Genric课程模板。

如果您没有使用提升,那么您可以自己实施any。在此站点上查找其实现或 type-erasure 。你肯定会有所了解。从这里开始:

答案 1 :(得分:2)

您将Genric定义为模板类,但之后尝试初始化t1而不给它类型。这就是你得到的错误。试试例如:

Genric<int> t1;

或者,如果您正在寻找真正的运行时通用,请查看 boost :: any

答案 2 :(得分:2)

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

如果你想要一些可以包含编译时未知的东西(更好:尚未知道),那么类型模板就不是解决方案。由于实际类型将在运行时才知道,因此您必须转向基于运行时的多态(从多态基础继承),最终包含在“处理程序”中。

从本质上讲,你需要一个基于虚拟函数的基础,它允许你检查类型,以及以all类型的合适方式实现该函数的泛型派生类。

boost :: any可以是一个实现,但可以有更简单的方法,特别是考虑到“允许发现运行时类型的函数”不超过...... dynamic_cast

你可以这样来解决这个问题

#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";
}

关注Abhinav评论:

由于C ++类型系统是静态的,你不能 - 通常 - 反序列化“未知”,除非你首先反序列化可以“知道”的东西。

为此,您首先需要一种方法将C ++类型(非对象)重新设置为可识别的值(类型为-uid),以及创建适用于这些“值”的包装器的“工厂”。

在保存时,您只需保存那个 uid,然后通过common_base虚函数请求保存包装的值。 在加载时,首先加载uid,然后创建一个具有适当类型的新包装器(见后),然后通过common_base虚函数加载该值。

要创建适当的包装器,您需要一个表,该表将uid-s映射到创建与uid类型关联的包装器的函数。 必须为您需要能够序列化/反序列化的所有类型预先初始化此表。

但这远远超出了您的原始问题,而不是关于序列化/反序列化。

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

相关问题