Ich denke, dass diese Aufgabe sehr häufig ist, aber ich kann keine richtige Lösung für sie finden.Wie man eine Fabrik für Templates richtig implementiert
Ich habe eine Hierarchie von „Produkten“, die einige „Traits“ hat, so habe ich beschlossen, auf Vorlagen basierende Schnittstelle für Produkte zu verwenden, in dem der Template-Parameter ist der „Zug“:
Diese sind Merkmale:
struct Foo {
static std::string get_name() { return "Foo"; }
Foo(int a) : a_(a) {}
int operator()() const { return a_; }
private:
int a_;
};
struct Bar {
static std::string get_name() { return "Bar"; }
Bar(int a, int b) : a_(a), b_(b) {}
int operator()() const { return a_ + b_; }
private:
int a_;
int b_;
};
struct Spam {
Spam(int a, int b) : a_(a), b_(b), c_(0) {}
void operator()() { c_++; }
private:
int a_;
int b_;
int c_;
};
und diese sind Produkte Hierarchie:
template <class T>
class Product {
public:
typedef T T_type;
virtual T get() = 0;
virtual ~Product() {}
};
template <class T>
class ProductA : public Product<T> {
typedef Product<T> base_type;
public:
ProductA(int a) : a_(a) {}
virtual ~ProductA() {}
virtual T get() {
return T(a_);
}
private:
int a_;
};
template <class T, class U>
class ProductB : public Product<T> {
typedef Product<T> base_type;
public:
typedef U U_type;
ProductB(int a, int b) : a_(a), b_(b) {}
virtual ~ProductB();
virtual T get() {
init(); // U is being used here
return T(a_, b_);
}
protected:
void init() {}
private:
int a_;
int b_;
};
ich brauche zusätzliche Ebene der Vererbung zu verwenden, da verschiedene Schnittstellen von ProductA
und ProductB
- sie haben unterschiedliche C-Tors.
Und hier sind konkrete Produkte:
class ProductA1 : public ProductA<Foo> {
typedef ProductA<Foo> base_type;
public:
ProductA1(int a) : base_type(a) { std::cout << "A1 created" << std::endl; }
virtual ~ProductA1() { std::cout << "A1 deleted" << std::endl; }
};
class ProductB1 : public ProductB<Bar, Spam> {
typedef ProductB<Bar, Spam> base_type;
public:
ProductB1(int a, int b) : base_type(a, b) { std::cout << "B1 created" << std::endl; }
virtual ~ProductB1() { std::cout << "B1 deleted" << std::endl; }
};
Jetzt habe ich einen Mechanismus der „unified“ Schaffung von Produkten haben will (in diesem Beispiel zwei Typen ProductA1
und ProductB1
) irgendwie mit der Zeichenfolge in eine Methode übergeben . Offensichtlich muss ich die Fabrik ...
So implementiert I Fabriken für verschiedene Zweige der Hierarchie (auf Objekte der Typen erstellen ProductA
und ProductB
), so dass ich Objekte vorbei ihre Typen durch den Template-Parameter erstellen konnte:
template <class P>
struct ProductAFactory {
typedef typename P::T_type T_type;
typedef ProductA<T_type> product_type;
static
product_type* create(int a) {
return new P(a);
}
};
template <class P>
struct ProductBFactory {
typedef typename P::T_type T_type;
typedef typename P::U_type U_type;
typedef ProductB<T_type,
U_type> product_type;
static
product_type* create(int a, int b) {
return new P(a, b);
}
};
diese Fabriken zu haben ich habe eine Fabrik soll haben Produkte der notwendigen Art konstruieren und einen Zeiger auf Produkt der Product<T>
Schnittstelle zurück:
template <class T>
class ProductFactory {
public:
static
Product<T>*
create(const std::string& product_name,
const int a,
const int b) {
const std::string product_a1 = "A1";
const std::string product_b1 = "B1";
if (product_name == product_a1)
return ProductAFactory<ProductA1>::create(a);
else if (product_name == product_b1)
return ProductBFactory<ProductB1>::create(a, b); // (*) <--- compiler error
else
throw std::runtime_error("Unsupported product: " + product_name);
}
};
Alle 0 diese Codes sollen in einer solchen Art und Weise verwendet werden:
void main() {
typedef Foo T;
std::shared_ptr<Product<T>> p(ProductFactory<T>::create("A1", 1, 1));
T t = p->get();
std::cout << t.get_name() << ": " << t() << std::endl;
}
Und hier stand ich mit einem Problem, diesen Code kompilieren - der Fehler ist return value type does not match the function type
bei (*)
. Es scheint, dass ProductB<Foo, Spam>
nicht automatisch in seinen Basistyp konvertiert werden kann
Ich bin kein guter Fabrikentwickler, vielleicht verstehe ich nicht die grundlegenden Prinzipien und Konzepte. Könnte jemand helfen, diesen Code oder diesen Ansatz zu korrigieren? Vielen Dank!
Ok, vielleicht verstehe ich die polymorphe Beziehung zwischen Templates wirklich falsch, aber könnten Sie mir raten, wie dieses Problem gelöst werden könnte? Ist es möglich, eine Fabrik zu implementieren, die ein Templatobjekt erzeugt? – lexxa2000
'' Sie scheinen zu denken, dass diese Typen irgendwie durch Vererbung verwandt sind'' - natürlich, ich nicht :) Ich schrieb diesen Code, um ein Konzept zu demonstrieren - es wird nicht kompilieren, weil in einer Funktion zwei verschiedene Typen zurückgegeben werden . – lexxa2000
Siehe mein Update zu der obigen Antwort, einschließlich der Live-Demo – Smeeheey