2016-07-29 19 views
1

Ich habe eine wirklich hässliche Implementierung von etwas, das ich umgestalten möchte, aber ich bin nicht sicher, wie. Hier ist, was ich habe:Wie man virtuelle Anrufe von nicht vorgestandenen Elternteilen sauber an Vorlagen schickt

Einige Templat-Objekt

template< typename T> 
class Thing { }; 

Eine Schnittstelle

class IService { 
    public: 
      virtual void func(void* arg) = 0; 
}; 

Ein Templat-Klasse Implementierung es

template< typename T> 
class Service< T> : public IService { 
    virtual void func(void* arg) { 
      func((Thing< T>*)arg); 
    } 
    void func(Thing< T>* arg) { 
      // do something with arg 
    } 
}; 

Der Grund ist, dass ich eine nicht wollen templated IService, den ich weitergeben kann. templating IService wird durch eine große Codebasis einen massiven Refactor verursachen.

Also instanziiere ich Service < T> Objekte, übergeben Sie die IService, und rufen Sie Func mit Vorlagen thing Objekte, die eine hässliche Umwandlung in eine ähnliche Funktion, die das eigentliche Thing-Objekt übernimmt. Gibt es einen sauberen Weg, dies zu erreichen, ohne IService zu templatieren?

Edit: etwas mehr Kontext. Dies ist, was ich wirklich will:

template<typename T> 
class IService { 
    public: 
      virtual void func(Thing<T>* arg) = 0; 
}; 

Allerdings kann ich nicht Vorlage IService.

+0

Könnten Sie mehr Kontext dazu liefern, was Sie zu tun versuchen? –

+0

Also muss jeder gegebene 'Service' das gleiche' T' wie das 'Ding' haben? Was ist, wenn ich 'Thing t anrufe; myIService-> func (t) 'wobei' meinIService' ein 'Service ' ist? – David

+0

@VittorioRomeo hinzugefügt – Erix

Antwort

2

Unter der Annahme, dass Sie nicht wollen oder können Thing eine Basisklasse nicht geben, und da eine gegebene Service<T> nur Thing s verarbeiten kann, die die gleiche T haben, können Sie dies tun:

class IService { 
    public: 
     template <typename T> 
     void func(Thing<T>* arg) { 
      auto self = dynamic_cast<Service<T>*>(this); 
      if (self) { 
       self->func(arg); 
      } else { 
       // decide how to handle this error 
      } 
     } 
}; 

func wäre nicht virtuell. Es ist nur eine Vorlagenrichtlinie, die von IService stammt, muss eine func(Thing<T>*) Methode haben.

+0

Dies ist eine gute Antwort, da es nicht viel mehr als das, was das OP gesagt hat, annimmt. Allerdings sollte self> func (arg) eine andere Methode aufrufen, denn wenn der Dienst (der von IService erbt) keine eigene func (arg) -Methode hat, wird er diese aufrufen und in einer rekursiven Schleife stecken bleiben .Mit einer anderen Methode erhalten Sie sogar eine Kompilierzeitüberprüfung, dass der Dienst über die entsprechende Methode verfügt – Altainia

1

Vielleicht würde eine Schnittstelle für die Thing würde den Trick tun?

class IThing { }; 

template< typename T> 
class Thing: public IThing { }; 

class IService { 
    public: 
      virtual void func(IThing* arg) = 0; 
}; 

template< typename T> 
class Service: public IService { 
    virtual void func(IThing* arg) { 
     Thing<T> *thing = dynamic_cast<Thing<T> *>(arg); 
     if (thing) { 
      // implementation 
     } 
    } 
}; 
1

Ich nehme an, Sie wollen typLösch Thing ‚s <T> Template-Parameter durch die Verwendung einer nicht-Templat-IService Klasse und dass Sie nicht über T bei der Umsetzung von IService kümmern. Ich bin mir nicht sicher, ob diese Annahme richtig ist, aber hier ist eine mögliche Lösung.

Ich gehe auch davon aus, dass virtual Versand innerhalbin Ihrem Anwendungsfall ausreichen.

// Create a `ThingBase` class to "type-erase" `Thing`'s 
// template parameter. `ThingBase` should contain your 
// `func`, as `virtual`. 
struct ThingBase 
{ 
    virtual void func(); 
}; 

// Your `Thing<T>` class should override `func` 
template <typename T> 
struct Thing : ThingBase 
{ 
    void func() override { /* ... */ } 
}; 

// Your `IService` now only needs to be as follows: 
struct IService 
{ 
    void func(ThingBase& x) 
    { 
     x.func(); 
    } 
};