C++是否有可能拥有一个具有不同类型参数的专用模板对象的容器?
我有一个模板类可以(或必须)专门的参数。 我想把我的所有参数放在一个容器中。 如何做到这一点,如果我的参数与不同类型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();
}
你可以使用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";
}
你最近的评论是好的,但问题仍然存在:如何存储参数与任何类型instanciated?你有使用Boost.Any的例子吗? – user1132852 2012-01-05 20:57:04
@ user1132852我发布了一个关于如何使用Boost.Any的极简例子。 – 2012-01-05 21:39:45
Boost.Any看起来像是矫枉过正; OP想要包含相关类型,而不是_any_类型。向量<:any>似乎没有让您将容器限制为Parameter对象。你从Boost获得什么优势?在这里,你不能从简单的dynamic_cast获得? – bacar 2012-01-05 23:16:41
容器内每一件事必须是同一类型。我做了一些类似于你的方法,我做了一个基类,它有一些有用的通用接口,派生类是模板化的。解决方案的唯一方法是定义一个基类函数来返回一个值来指示类型,然后向下转换基类。
正确的解决办法是写的基础类不够好接口,这样你可以做你需要做的一切:
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;
};
虽然这可能不是你想要的,它仍然允许传递值从下一个参数。一旦你想要实际的值,你需要知道编译时的类型。该类型的开关大小可能有助于使其运行。
像这样使用'void *'很容易出错。我一定会把它改成'boost :: any'。 – 2012-01-05 20:47:04
是的,但为了在我的Container类中切换大小写,我需要知道所有的情况> – user1132852 2012-01-05 20:53:44
它不会比使用any_cast更容易出错。 downcast操作总是很危险,void *只是记录在这里发生了一些危险的事情。 – tp1 2012-01-05 21:36:20
你是什么意思由Qstring“与ostream不兼容”,它与这个问题有什么关系?你是否想要调用参数 :: getFoo()?你可以提供一个方法让operator
bacar
2012-01-05 20:39:57
你到底想要做什么?如何使用Base不能解决您的问题?这听起来像你想要的东西是通用的多种类型,同时具有一些特定于该类型的功能(“我们无法在Container :: foo中专门做任何事情”) - 我不确定如何在没有向下转换的情况下有效实现这一点。 – bacar 2012-01-05 20:41:51
@bacar模板类中的getFoo()不适用于QString。我们必须使用:s < < val.toStdString()。
– user1132852 2012-01-05 20:48:45