2012-01-05 67 views
2

我有一个模板类可以(或必须)专门的参数。 我想把我的所有参数放在一个容器中。 如何做到这一点,如果我的参数与不同类型instanciated?C++是否有可能拥有一个具有不同类型参数的专用模板对象的容器?

在类容器,我希望有不同类型(int,双...)或等同的东西的载体<参数* >这似乎是不可能的。

如果Parameter类是从基类派生的,那么The Container可以声明vect为向量< Base * >。但在这种情况下,我们无法在Container :: foo中做任何具体的操作。

以下是我的源代码示例。我的一个参数是一个与ostream不兼容的QString。

感谢您的意见。



    #include <QString> 
    #include <vector> 
    #include <iostream> 
    #include <string> 
    #include <sstream> 
    using namespace std; 

    #define P(a) cout << #a << ":" << a << endl 

    /* 
    class Base { 

    }; 
    */ 

    template<typename T> class Parameter /*: public Base */ { 
    private: 
     T val; 
    public: 
     void setVal(const T &val) { 
      this->val = val; 
     } 
     const T &getVal() { 
      return val; 
     } 
     string getFoo() { 
      stringstream s; 
      s << val; 
      return s.str(); 
     } 
    }; 

    template<> 
    string Parameter<QString>::getFoo() { 
     stringstream s; 
     s << val.toStdString(); 
     return s.str(); 
    } 

    class Container { 
    public: 
     void push_back(Parameter *base) { 
      vect.push_back(base); 
     } 
     void foo() { 
      /* do something with the parameters */ 
     } 
    private: 
     vector<Parameter*> vect; 
    }; 

    int main() { 
     Parameter<int> pi; 
     Parameter<QString> ps; 

     pi.setVal(10); 
     ps.setVal("QString"); 

     P(pi.getVal()); 
     P(ps.getVal().toStdString()); 

     P(pi.getFoo()); 
     P(ps.getFoo()); 

     Container container; 
     container.push_back(&pi); 
     container.push_back(&ps); 
    } 

非常感谢您的意见。我会按照你的意见,并使用boost :: any。 以下是更新版本:



    #include <boost/any.hpp> 
    #include <QString> 
    #include <vector> 
    #include <iostream> 
    #include <string> 
    #include <sstream> 
    using namespace std; 

    #define P(a) cout << #a << ":" << a << endl 

    template<typename T> class Parameter { 
    private: 
     T val; 
    public: 
     void setVal(const T &val) { 
      this->val = val; 
     } 
     const T &getVal() { 
      return val; 
     } 
     string getFoo() { 
      stringstream s; 
      s << val; 
      return s.str(); 
     } 
    }; 

    template<> 
    string Parameter<QString>::getFoo() { 
     stringstream s; 
     s << val.toStdString(); 
     return s.str(); 
    } 

    class Container { 
    public: 
     void push_back(boost::any base) { 
      vect.push_back(base); 
     } 
     void foo() { 
      cout << "do something with the parameters\n"; 
      for (vector<boost::any>::iterator i = vect.begin(); i != vect.end(); ++i) { 
       boost::any a = (*i); 
       if (a.type() == typeid(Parameter<int>*)) { 
        Parameter<int> *ai = boost::any_cast<Parameter<int> *>(a); 
        cout << ai->getFoo() << endl; 
       } else if (a.type() == typeid(Parameter<QString>*)) { 
        Parameter<QString> *aq = boost::any_cast<Parameter<QString> *>(a); 
        cout << aq->getFoo() << endl; 
       } else { 
        cout << "unknown type:" << a.type().name() << endl; 
       } 
      } 
     } 
    private: 
     vector<boost::any> vect; 
    }; 

    int main() { 
     Parameter<int> pi; 
     Parameter<QString> ps; 

     pi.setVal(10); 
     ps.setVal("QString"); 

     P(pi.getVal()); 
     P(ps.getVal().toStdString()); 

     P(pi.getFoo()); 
     P(ps.getFoo()); 

     Container container; 
     container.push_back(&pi); 
     container.push_back(&ps); 
     container.foo(); 
    } 



+0

你是什么意思由Qstring“与ostream不兼容”,它与这个问题有什么关系?你是否想要调用参数 :: getFoo()?你可以提供一个方法让operator <<自己工作,如果它有意义的话。 – bacar 2012-01-05 20:39:57

+0

你到底想要做什么?如何使用Base不能解决您的问题?这听起来像你想要的东西是通用的多种类型,同时具有一些特定于该类型的功能(“我们无法在Container :: foo中专门做任何事情”) - 我不确定如何在没有向下转换的情况下有效实现这一点。 – bacar 2012-01-05 20:41:51

+0

@bacar模板类中的getFoo()不适用于QString。我们必须使用:s < < val.toStdString()。
user1132852 2012-01-05 20:48:45

回答

2

你可以使用Boost.Any可以容纳任何类型的数据。然后,您将使用boost::any_cast<>将对象转换回正确的类型。

除此之外,您将不得不采用基类方法,但正如您所提到的那样,要使Container::foo做任何有用的操作都很困难。

解决此问题的一种方法是让所有foo函数都将字符串作为参数,然后函数的每个特定实现将解析该字符串并将其转换为正确的类型。

编辑: Boost.Any例如:

#include <iostream> 
#include <boost/any.hpp> 

int main() 
{ 
    boost::any param = 89; 

    // This will fail because `param` is currently holding an int 
    // not a char 
    char ch = boost::any_cast<char>(param); 

    // This works 
    int i = boost::any_cast<int>(param); 

    // You can always change the value and type of what 
    // `param` is holding 
    param = "example"; 
} 
+0

你最近的评论是好的,但问题仍然存在:如何存储参数与任何类型instanciated?你有使用Boost.Any的例子吗? – user1132852 2012-01-05 20:57:04

+0

@ user1132852我发布了一个关于如何使用Boost.Any的极简例子。 – 2012-01-05 21:39:45

+0

Boost.Any看起来像是矫枉过正; OP想要包含相关类型,而不是_any_类型。向量似乎没有让您将容器限制为Parameter对象。你从Boost获得什么优势?在这里,你不能从简单的dynamic_cast获得? – bacar 2012-01-05 23:16:41

0

容器内每一件事必须是同一类型。我做了一些类似于你的方法,我做了一个基类,它有一些有用的通用接口,派生类是模板化的。解决方案的唯一方法是定义一个基类函数来返回一个值来指示类型,然后向下转换基类。

2

正确的解决办法是写的基础类不够好接口,这样你可以做你需要做的一切:

class Base { 
public: 
    virtual void *GetVal() const=0; 
    virtual void SetVal(void *ptr)=0; 
    virtual std::string Type() const=0; 
    virtual std::string GetAsString() const=0; 
}; 

虽然这可能不是你想要的,它仍然允许传递值从下一个参数。一旦你想要实际的值,你需要知道编译时的类型。该类型的开关大小可能有助于使其运行。

+1

像这样使用'void *'很容易出错。我一定会把它改成'boost :: any'。 – 2012-01-05 20:47:04

+0

是的,但为了在我的Container类中切换大小写,我需要知道所有的情况> – user1132852 2012-01-05 20:53:44

+0

它不会比使用any_cast更容易出错。 downcast操作总是很危险,void *只是记录在这里发生了一些危险的事情。 – tp1 2012-01-05 21:36:20

相关问题