Polymorphic factory - c++

Consider the following code:
template <typename T>
class DrawerFactory
{
protected:
DrawerFactory() {};
private:
virtual shared_ptr<IDrawer> GetDrawer(T settings) = 0;
};
class ConcreteDrawerFactoryA : public DrawerFactory<SettingsA>
{
public:
shared_ptr<IDrawer> GetDrawer(SettingsA settingsA) override
{
if (settingsA.style == A) return make_shared<ConcreteDrawerA>(settingsA.length, settingsA.stroke, settingsA.opacity);
else return make_shared<ConcreteDrawerB>(20, .5);
};
};
class ConcreteDrawerFactoryB : public DrawerFactory<SettingsB>
{
public:
shared_ptr<IDrawer> GetDrawer(SettingsB settingsB) override
{
if (settingsB.type == TYPEC) return make_shared<ConcreteDrawerC>(settingsB.width, settingsB.height);
else return make_shared<ConcreteDrawerD>(10, 2);
};
};
I can get a drawer by:
ConcreteDrawerFactoryA().GetDrawer(settingsa);
or
ConcreteDrawerFactoryB().GetDrawer(settingsb);
What I'd like to do is:
DrawerFactory().GetDrawer(settingsa);
DrawerFactory().GetDrawer(settingsb);
Is there a way to set this up without having to continually add overloads to DrawerFactory for each concrete factory I want to add?

Instead of factory hierarchy and virtual dispatch you could make use of templates and specialization:
#include <memory>
struct IDrawer { };
struct Drawer1: IDrawer { };
struct Drawer2: IDrawer { };
struct Drawer3: IDrawer { };
struct Drawer4: IDrawer { };
template <class T>
struct DrawerGetterImpl;
struct DrawerFactory {
template <class T>
std::shared_ptr<IDrawer> GetDrawer(T settings) {
return DrawerGetterImpl<T>::GetDrawer(settings);
}
};
struct SettingsA { int style; };
template <>
struct DrawerGetterImpl<SettingsA> {
static std::shared_ptr<IDrawer> GetDrawer(SettingsA settings) {
if (settings.style == 1) {
return std::make_shared<Drawer1>();
}
return std::make_shared<Drawer2>();
}
};
struct SettingsB { int type; };
template <>
struct DrawerGetterImpl<SettingsB> {
static std::shared_ptr<IDrawer> GetDrawer(SettingsB settings) {
if (settings.type == 1) {
return std::make_shared<Drawer3>();
}
return std::make_shared<Drawer4>();
}
};
int main() {
DrawerFactory().GetDrawer(SettingsA{1});
}
[live demo]

In your example, your factory seemed to have no state, so can you achieve what you want without a polymorphic factory? For example something like this...
template<class T>
std::shared_ptr<IDrawer> MakeDrawer(T settings);
template<>
std::shared_ptr<IDrawer> MakeDrawer<SettingsA>(SettingsA settings)
{
return std::make_shared<ConcreteDrawerA>(); // use settings really
}
template<>
std::shared_ptr<IDrawer> MakeDrawer<SettingsB>(SettingsB settings)
{
return std::make_shared<ConcreteDrawerB>(); //use settings here
}
void main()
{
SettingsA setA;
std::shared_ptr<IDrawer> pA = MakeDrawer(setA);
SettingsB setB;
std::shared_ptr<IDrawer> pB = MakeDrawer(setB);
}
You could use overloads instead of templates.

Related

Abstract class with template function issue

I have an abstract struct I with method a. B and B2 will inherit from it. X struct has an I type member and will instantiate it via createInsance template method based on type. I want to have on B2 an additional function b2Exclusive but I got compilation error that it is not present in A.
error: ‘using element_type = struct B’ {aka ‘struct B’} has no member named ‘b2Exclusive’
Is any way for solving this without defining b2Exclusive for B as well and to keep to structure this way?
#include <iostream>
#include <memory>
using namespace std;
struct I
{
virtual void a() = 0;
};
struct B : public I
{
B()
{
std::cout<<"B\n";
}
void a()
{
std::cout<<"-a from B\n";
}
};
struct B2 : public I
{
B2()
{
std::cout<<"B2\n";
}
void a()
{
std::cout<<"-a from B2\n";
}
void b2Exclusive()
{
std::cout<<"-something for B2\n";
}
};
using Iptr = std::shared_ptr<I>;
struct X
{
void createI()
{
if (type == "B")
{
createInstance<B>();
}
else
{
createInstance<B2>();
}
}
template <typename T>
void createInstance()
{
auto i = std::make_shared<T>();
if (type == "B2")
{
i->b2Exclusive();
}
}
std::string type = "None";
};
int main()
{
X x;
x.type = "B2";
x.createI();
return 0;
}
You can only call b2Exclusive if the template function use typename B2: one way to do so is to create the specialization for that type, such as this for example:
struct X
{
void createI();
template <typename T>
void createInstance()
{
//do something
}
std::string type = "None";
};
template<>
void X::createInstance<B2> ()
{
auto i = std::make_shared<B2>();
i->b2Exclusive();
}
void X::createI()
{
if (type == "B")
{
createInstance<B>();
}
else
{
createInstance<B2>();
}
}
int main()
{
X x;
x.type = "B2";
x.createI();
return 0;
}

Select a template specialization by enum values for static polimorphism

Here is simplified sample of problem, featuring CRTP:
#include <type_traits>
#include <iostream>
enum ActionTypes {
eInit = 2 << 0,
eUpdate = 2 << 1,
eMultUpdate = 2 << 2
};
template <class Data,
unsigned Actions = eInit|eUpdate|eMultUpdate>
class ActionData
{
template<ActionTypes As /*???*/>
struct action {
static void exec(Data*) { std::cout << "ActionData:: /*dummy*/ exec()\n"; };
static void exec(Data*,int) { std::cout << "ActionData::/*dummy*/ exec(int)\n"; };
};
template<>
struct action < /*???*/ >
{
static void exec(Data*) { /*...*/ };
};
template<>
struct action < /*???*/ >
{
static void exec(Data*, int) { /*...*/ };
};
Data* derived() { return static_cast<Data*>(this); }
protected:
void init() { action<eInit>::exec(derived()); }
void update() { action<eUpdate>::exec(derived()); }
void update(int key) { action<eMultUpdate>::exec(derived()); }
public:
enum Keys { DEFAULT_KEY = -1 };
void call(ActionTypes a, int key = DEFAULT_KEY)
{
switch (a) {
case eInit:
init(); break;
case eUpdate:
if (key == DEFAULT_KEY)
update();
else
case eMultUpdate:
update(key);
}
}
};
class Test : public ActionData<Test, eUpdate>
{
public:
void update() { std::cout << "Test :: update()\n"; }
};
int main()
{
Test actor;
ActionTypes a = eInit;
actor.call(a, 0); // useless here but must be possible.
actor.call(eUpdate, 0);
actor.call(eUpdate);
}
Essentially not all derived classes may implement all handlers, a enum is used to declare that and a dummy version of handler must be called. The problem is that it's not possible to select any implementation but default one using enum and enable_if alone, it requires a non-type parameter, which stupefied me.
PS. Another problem is target platform is limited to C++98\C++03 or tr1 C++11 (no variadic templates). The awkward interface is a legacy of dynamic (but not used as such) polymorphic architecture using function pointers in a big C (not C++!) project. Necessity of pointers or vtable made system unstable to programmer errors leading to vtable being overwritten.
I didn't realize that I should use a partial specialization for all cases including where there is no match:
#include <type_traits>
#include <iostream>
enum ActionTypes {
eInit = 2 << 0,
eUpdate = 2 << 1,
eMultUpdate = 2 << 2
};
template <class Data,
unsigned Actions = eInit|eUpdate|eMultUpdate>
class ActionData
{
// Never gets selected
template<ActionTypes A, typename Enable = void > struct action {};
template< ActionTypes A >
struct action<A, typename std::enable_if<(A & Actions) == 0>::type >
{
static void exec(Data*) { std::cout << "ActionData:: /*dummy*/ exec()\n"; };
static void exec(Data*,int) { std::cout << "ActionData::/*dummy*/ exec(int)\n"; };
};
template< ActionTypes A >
struct action < A, typename std::enable_if<(A & Actions) == eInit>::type >
{
static void exec(Data* o) { o->Data::init(); };
};
template< ActionTypes A >
struct action < A, typename std::enable_if<(A & Actions) == eUpdate>::type >
{
static void exec(Data* o) { o->Data::update(); };
};
template< ActionTypes A >
struct action < A, typename std::enable_if<(A & Actions) == eMultUpdate>::type >
{
static void exec(Data* o, int key) { o->Data::update(key); };
};
Data* derived() { return static_cast<Data*>(this); }
protected:
void init() { action<eInit>::exec(derived()); }
void update() { action<eUpdate>::exec(derived()); }
void update(int key) { action<eMultUpdate>::exec(derived(), key); }
public:
enum Keys { DEFAULT_KEY };
void call(ActionTypes a, int key = DEFAULT_KEY)
{
switch (a) {
case eInit:
init(); break;
case eUpdate:
if (key == DEFAULT_KEY) {
update();
break;
} else {
case eMultUpdate:
update(key);
break;
};
}
}
};
class Test : public ActionData<Test, eUpdate>
{
public:
void update() { std::cout << "Test :: update()\n"; }
};
int main()
{
Test actor;
ActionTypes a = eInit;
actor.call(a, 0);
actor.call(eUpdate);
actor.call(eMultUpdate, 0);
}

Store different templated classes in one container without losing information about it's type

I'm currently working on a project where a client part of my application has to be able to create custom templated classes on the server. The server part has to keep track of these created classes and has to remember the types with which the classes has been instantiated. The problem is, that there are around 36 different class-template-combinations that are valid in my application. I'm currently struggling to keep track of these different types in a collection without losing information about my instances.
I'm currently using something like this:
#include <memory>
#include <type_traits>
#include <vector>
enum class data_type : std::uint8_t {
type_int = 1,
type_float,
type_double
};
enum class class_type : std:: uint8_t {
type_A = 1,
type_B
};
struct X {
virtual data_type get_data_type() = 0;
virtual class_type get_class_type() = 0;
};
template <typename T>
struct A : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_A;
}
};
template <typename T>
struct B : X {
data_type get_data_type() override
{
if (std::is_same<T, int>::value) {
return data_type::type_int;
} else if (std::is_same<T, float>::value) {
return data_type::type_float;
} else if (std::is_same<T, double>::value) {
return data_type::type_double;
} else {
/* ... */
}
}
class_type get_class_type() override
{
return class_type::type_B;
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
but I'm wondering if this is the way to go or if there is a more elegant way. Here I would have to always switch through the enums to get the full type out of my Storage class, something like:
switch(_classes.front()->get_class_type()) {
case class_type::type_A:
{
switch(_classes.front()->get_data_type()) {
case data_type::type_int:
{
/* I finally know that it is A<int> */
}
/* ... */
Thanks in advance.
You can consider using std::variant and the std::visit pattern
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit([](auto& value) {
using Type = std::decay_t<decltype(value)>;
if constexpr (std::is_same<Type, int>{}) {
// is an int
} else if (std::is_same<Type, float>{}) {
// is float
} else if (std::is_same<Type, double>{}) {
// is double
}
}, var);
If the if constexpr looks ugly to you then you can substitute it with a handrolled visitor class as well.
class Visitor {
public:
void operator()(int& value) { ... }
void operator()(float& value) { ... }
void operator()(double& value) { ... }
};
auto var = std::variant<int, float, double>{};
// assign var to value
std::visit(Visitor{}, var);
As mentioned in the comments to the question, this is a viable approach that could help:
#include<vector>
#include<memory>
struct Counter {
static int next() {
static int v = 0;
return v++;
}
};
template<typename>
struct Type: Counter {
static int value() {
static const int v = Counter::next();
return v;
}
};
struct X {
virtual int get_data_type() = 0;
virtual int get_class_type() = 0;
};
template <typename T>
struct A : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<A<T>>::value();
}
};
template <typename T>
struct B : X {
int get_data_type() override {
return Type<T>::value();
}
int get_class_type() override {
return Type<B<T>>::value();
}
};
struct Storage {
template <typename T, template <typename> class Class>
void create() {
Class<T>* t = new Class<T>();
_classes.push_back(std::unique_ptr<X>(t));
}
std::vector<std::unique_ptr<X>> _classes;
};
int main() {
Storage s;
s.create<int, A>();
if(Type<int>::value() == s._classes.front()->get_class_type()) {
//...
};
}
See it running on wandbox.

Specialize member function of a templated derived class

I have the following code (very simplified for the sake of clarity):
class Base
{
virtual int DoStuff(int arg) = 0;
};
template <typename T>
class Derived : public Base
{
int DoStuff(int arg) override
{
// do some stuff
return 0;
}
};
This works great. Now I want to implement a special (vectorized) implementation of DoStuff. And I need the implementation to be specific based on the type T that Derived has, something like this:
class Base
{
virtual int DoStuff(int arg) = 0;
virtual int DoStuffVectorized(int arg) = 0;
};
template <typename T>
class Derived : public Base
{
int DoStuff(int arg) override
{
// do some stuff
return 0;
}
int DoStuffVectorized<char>(int arg) override
{
// do some stuff for T == char
return 0;
}
int DoStuffVectorized<int>(int arg) override
{
// do some stuff for T == int
return 0;
}
};
However i'm unable to make this work.
EDIT:
I get the following error message: error C2143: syntax error: missing ';' before '<' on the line int DoStuffVectorized<char>(int arg) override.
When i change it to:
template<char> int DoStuffVectorized(int arg) override i get: error C2898: ...': member function templates cannot be virtual
Any advice on how to achieve something like this? The reason i need it is that i have a std::vector that stores data of various types (by using Derived<>). This way i can use the same simple code regardless of the type being stored and i want this to be true even when using the special vectorized implementation of DoStuff that is sadly type specific.
You have to specialize template member functions outside of the class:
#include <iostream>
class Base
{
public:
virtual int DoStuffVectorized(int arg) = 0;
};
template <typename T>
class Derived : public Base
{
public:
int DoStuffVectorized(int arg) override;
};
template <>
int Derived<char>::DoStuffVectorized(int arg)
{
std::cout << "T == char\n";
return 0;
}
template <>
int Derived<int>::DoStuffVectorized(int arg)
{
std::cout << "T == int\n";
return 0;
}
int main(){
Derived<char> c;
Derived<int> i;
Base* b[] = { &c, &i };
for(auto* x : b)
x->DoStuffVectorized(0);
// undefined reference to `Derived<double>::DoStuffVectorized(int)'
// Derived<double> d;
}
If you want to capture unintended instantiations at compile time:
#include <type_traits>
// A std::false_type (useful in a static_assert)
template <typename T>
struct static_false : std::false_type
{};
template <typename T>
int Derived<T>::DoStuffVectorized(int arg)
{
static_assert(static_false<T>::value, "Neither 'char' or 'int'");
return 0;
}
DoStuffVectorized<char> is not correct syntax, DoStuffVectorized isn't template itself.
See template specialization:
template <typename T>
class Derived : public Base
{
int DoStuff(int arg) override
{
// do some stuff
return 0;
}
int DoStuffVectorized(int arg) override
{
// do some stuff (primary template)
return 0;
}
};
template <>
int Derived<int>::DoStuffVectorized(int) {
// do some stuff for T == char
return 0;
}
template <>
int Derived<char>::DoStuffVectorized(int) {
// do some stuff for T == char
return 0;
}

Member functions "name" in trait class? (generic adaptor)

I have implemented a Policy using the CRTP. The policy requires the Base class to have a function called foo:
template<typename Base>
struct Policy<Base> {
// ...
Base* b(){ return static_cast<Base*>(this); }
void do(){ b()->foo(); }
};
I have one class called Widget that uses my policy. Widget implements foo and everything is fine:
struct Widget : Policy<Widget> {
// ...
void foo();
};
The problem: I also have a type called OldWidget that implements the functionality of foo in a function named oldFoo:
struct OldWidget : Policy<OldWidget> {
// ...
void oldFoo();
};
I don't want to modify OldWidget (besides extending it with the policy). I don't want to use an AdaptedOldWidget:
struct AdaptedOldWidget : OldWidget, Policy<AdaptedOldWidget> {
void foo(){ oldFoo(); }
};
The best would be to extend my existing policy_traits class to something like:
template<typename T>
struct policy_traits {};
template<>
struct policy_traits<Widget> {
// typedefs...
member_function_name = foo;
};
template<>
struct policy_traits<OldWidget> {
// typedefs
member_function_name = oldFoo;
};
Such that I can implement the Policy like this:
template<typename Base>
struct Policy<Base> {
// ...
Base* b() { return static_cast<Base*>(this); }
void do(){ b()->policy_traits<Base>::member_function_name(); }
};
Is there away to achieve something like this in C++?
Proposed solution: I could do the following:
template<typename Base>
struct Policy<Base> : Policy_Member_Traits<Base> {
// ...
Base* b(){ return static_cast<Base*>(this); }
void do(){ foo_wrapper(); }
};
template<typename T> struct Policy_Member_Traits { };
template<> struct Policy_Member_Traits<Widget> {
void foo_wrapper(){ static_cast<T*>(this)->foo(); }
};
template<> struct Policy_Member_Traits<OldWidget> {
void foo_wrapper(){ static_cast<T*>(this)->oldFoo(); }
};
There must be hopefully a better easier way to achieve this.
first of all: signature of all functions must be the same. then you may set a static member w/ member-function address inside of your policy_traits, so you'll be able to call desired function later (from your Policy template) using it.
typedef void (*void_memfn_type)();
template<>
struct policy_traits<Widget> {
static void_memfn_type const member_function_name = &Widget::foo;
};
template<>
struct policy_traits<OldWidget> {
static void_memfn_type const member_function_name = &OldWidget::oldFoo;
};
then:
template<typename Base>
struct Policy<Base> {
// ...
Base* b() { return static_cast<Base*>(this); }
void do(){ b()->policy_traits<Base>::(*member_function_name)(); }
};
Here's an example how specializing selectively. First, some example classes:
#include <iostream>
struct Foo
{
void foo() const { std::cout << "Foo::foo\n"; }
void bar() const { std::cout << "Foo::foo\n"; }
};
struct Biz
{
void old_foo() const { std::cout << "Fiz::old_foo\n"; }
void bar() const { std::cout << "Fiz::foo\n"; }
};
struct Fiz
{
void foo() const { std::cout << "Biz::foo\n"; }
void old_bar() const { std::cout << "Biz::old_foo\n"; }
};
Now the trait:
template <typename T> struct Dispatch
{
static void foo(T const & x) { x.foo(); }
static void bar(T const & x) { x.bar(); }
};
template <> void Dispatch<Biz>::foo(Biz const & x) { x.old_foo(); }
template <> void Dispatch<Fiz>::bar(Fiz const & x) { x.old_bar(); }
And here's a usage example:
template <typename T> void dispatch(T const & x)
{
Dispatch<T>::foo(x);
Dispatch<T>::bar(x);
}
int main()
{
Foo f;
Biz b;
Fiz c;
dispatch(f);
dispatch(b);
dispatch(c);
}