0

下面的代码更改为使用智能指针:

我有一个模板类:

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)
4

3 回答 3

3

最简洁的答案是不。 Request<int>并且Request<double>是不同的类型,并且Request本身不是类型。您的getRequest方法无效,因为您在不同的情况下返回不同的类型。

解决此问题的一种方法是拥有一个Request继承的基类,例如IRequest. IRequest然后,您可以在 getRequest 方法中返回一个指向 a 的(智能)指针。

请注意,您将无法调用模板类中的当前方法,因为您无法将它们指定为基类中的虚函数。但是,您可以将您的调用方法作为纯虚函数移动到您的基类中,从而允许在模板类中实现它。

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;
};
于 2013-08-07T12:41:39.367 回答
2

您可以为此使用Boost Variant。它不仅可以让您声明可以返回的单一类型的请求,还可以声明一组特定的、有限的请求。或者您可能决定让您的请求在内部包含一个变体,而不是作为模板类型本身。

或者,您可以让 Request 有一个虚拟基础并实现Visitor Pattern

于 2013-08-07T12:41:38.330 回答
0

您可以创建一个IRequest不是模板类的抽象类,并让您的模板类扩展它。

然后,您必须将方法的签名更改为:

IRequest& getRequest(int which)

与此类似, 更改Requestrun()invoke()。您还必须确保对象的内存是动态分配的,而不是自动分配的。IRequest&

于 2013-08-07T12:41:50.507 回答