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() がファイルから値を読み取っているため、受信したあらゆるタイプの要求を処理できる必要があります。任意のタイプを含めることができます。

コンパイラはこれを好みません。run() メソッドと invoke() の呼び出しの両方で、Request が角かっこで囲まれた型を持つことを期待しています。また、getRequest() の戻り値の型に山かっこがあることも想定しています。

任意の型のテンプレート オブジェクトを保持して渡すための C++ メカニズムはありますか?

呼び出しをそのままにするか、次のように変更する必要があります。

void invoke<IRequest& request)
4

3 に答える 3

3

短い答えはノーです。 Request<int>Request<double>は異なる型でありRequest、それ自体は型ではありません。さまざまgetRequestなケースでさまざまな型を返すため、メソッドは無効です。

これを回避する方法の 1 つは、Request継承する基底クラスを作成することIRequestです。IRequest次に、getRequest メソッドで(スマート) ポインターを に返すことができます。

基本クラスで仮想関数として指定できないため、テンプレート化されたクラスで現在のメソッドを呼び出すことができないことに注意してください。ただし、呼び出しメソッドを純粋な仮想関数として基本クラスに移動して、テンプレート化されたクラスに実装できるようにすることもできます。

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 だけでなく、それらの特定の限定されたセットを宣言できます。または、テンプレート化されたタイプ自体ではなく、リクエストにバリアントを内部に含めることを決定する場合があります。

または、 Request に仮想ベースを持たせ、Visitor Patternを実装することもできます。

于 2013-08-07T12:41:38.330 に答える
0

テンプレート クラスではない抽象クラスを作成しIRequest、それをテンプレート クラスに拡張させることができます。

次に、メソッドの署名を次のように変更する必要があります。

IRequest& getRequest(int which)

同様に、とをに変更Requestします。 また、オブジェクトのメモリが自動割り当てではなく動的に割り当てられていることを確認する必要があります。run()invoke()IRequest&

于 2013-08-07T12:41:50.507 に答える