下面的代码更改为使用智能指针:
我有一个模板类:
class IRequest;
template<class T>
class Request : public IRequest
{
public:
Request(T in) : m_data(in) {}
virtual ~Request() {}
T get() { return m_data; }
void set(T in) { m_data = in; }
private:
T m_data;
}
在另一个课程中我有方法:
template<T>
void invoke(Request<T>& request)
{
// Do some stuff
}
std::unique_ptr<IRequest> getRequest(int which)
{
switch(which)
{
case 1: return std::unique_ptr<IRequest>(new Request<int>(1));
case 2: return std::unique_ptr<IRequest>(new Request<bool>(true));
case 3: return std::unique_ptr<IRequest>(new Request<double>(2.0));
default: throw std::exception();
}
}
void run()
{
int type = getRequestType();
std::unique_ptr<IRequest> request = getRequest(type);
invoke(*request);
}
问题是这样,run()方法不能模板化,必须只有1个或者它们, 并且它需要能够处理它接收的任何类型的请求,如getRequestType() 正在读取文件中的值,该文件可以包含任何类型。
编译器不喜欢这样,它希望Request在斜角括号中有一个类型, run()方法和invoke()调用。它还期望返回类型 getRequest()具有斜角括号。
是否有用于保存和传递任何类型的模板对象的C ++机制?
使用智能指针时,调用应保持原样,或者应该更改为:
void invoke<IRequest& request)
答案 0 :(得分:3)
简短的回答是否定的。 Request<int>
和Request<double>
是不同类型,Request
本身不是类型。您的getRequest
方法无效,因为您在不同情况下返回不同的类型。
解决此问题的一种方法是拥有Request
继承的基类,例如IRequest
。然后,您可以在getRequest方法中返回一个(智能)指针到IRequest
。
请注意,您将无法调用模板化类中的当前方法,因为您无法在基类中将它们指定为虚函数。但是,您可以将调用方法作为纯虚函数移动到基类,允许它在模板化类中实现。
class IRequest
{
public:
virtual ~IRequest() { }
virtual void invoke() = 0;
};
template <typename T>
class Request : public IRequest
{
public:
Request(T in) : m_data(in) { }
virtual ~Request() { }
virtual void invoke() { /* Do stuff */ }
private:
T m_data;
};
答案 1 :(得分:2)
您可以使用Boost Variant。它不仅可以声明可以返回的单一类型的请求,还可以声明一组特定的有限请求。或者您可能决定让您的请求在内部包含变量,而不是自己的模板类型。
或者,您可以使Request具有虚拟基础并实现Visitor Pattern。
答案 2 :(得分:0)
您可以创建一个抽象类IRequest
,它不是模板类,并使您的模板类扩展它。
然后您必须将方法的签名更改为:
IRequest& getRequest(int which)
类似地,将Request
和run()
中的invoke()
更改为IRequest&
。
您还必须确保动态分配对象的内存,而不是自动分配。