Object Factory registration of template class hierarchy - c++11

I implemented a general object factory following the guidelines of Andrei Alexandrescu's book Modern C++ Design, so I can define a class hierarchy like this (I will write the code in the most simplified way, avoiding implementation details or memory allocation/deallocation issues; I'm aware of these things and I would like to focus the discussion on the main issue):
// File "base.h"
#include <string>
#include "singleton.h"
#include "object_factory.h"
class Base;
using SingletonBaseFactory = Singleton
<
ObjectFactory
<
Base, // Abstract product type
std::string, // Identifier type
Base* (*)() // Concrete product creator type
>
>;
class Base {
// Define the interface (virtual functions, virtual dtor)
public:
// Wrap the Factory method
static Base* Factory(const std::string& ID) {
return SingletonBaseFactory::Instance().Factory(ID);
}
};
// File "derived_1.h"
#include "base.h"
class Derived_1 : public Base { /* ... */ };
// File "derived_2.h"
#include "base.h"
class Derived_2 : public Base { /* ... */ };
and register each derived class within an anonymous namespace in the corresponding implementation file:
// File "derived_1.cpp"
#include "derived_1.h"
namespace {
Base* CreateDerived_1() {
return new Derived_1;
}
const bool registered = SingletonBaseFactory::Instance().Register("Derived_1", CreateDerived_1);
}
// Same for Derived_2 in file "derived_2.cpp"
Therefore, an user that wants to use this hierarchy in his code has just to invoke the Base::Factory method with a proper identifier:
// File main.cpp
#include"base.h"
int main(){
Base* pb = Base::Factory("Derived_1");
// Do stuff with pb
return 0;
}
Now, suppose I have a template class hierarchy, say:
// File "baset.h"
#include <string>
#include "singleton.h"
#include "object_factory.h"
template<class T>
class BaseT;
template<class T>
using SingletonBaseTFactory = Singleton
<
ObjectFactory
<
BaseT<T>, // Abstract product type
std::string, // Identifier type
BaseT<T>* (*)() // Concrete product creator type
>
>;
template<class T>
class BaseT {
/*Define the interface*/
public:
BaseT Factory(const std::string& ID) {
return SingletonBaseTFactory<T>::Instance().Factory(ID);
}
};
// File "derivedt_1.h"
#include "baset.h"
template<class T>
class DerivedT_1 : public BaseT<T> { /* ... */ };
In this case the registration is an user responsibility for each type T he wants to use, before using the class hierarchy:
// File main.cpp
#include "baset.h"
#include "derivedt_1.h"
bool register_derived_1_int = SingletonBaseTFactory<int>::Instance().Register("Derived_1", [](){ return new DerivedT_1<int>; });
int main() {
BaseT<int>* pb = BaseT<int>::Factory("Derived_1");
return 0;
}
Keeping in mind that the ID of each derived template class is the same for every type T, would it make sense to delegate the registration responsibility to the developer of each derived class (rather than the user) even in the templated case?
If so, is there a workaround to achieve it?
EDIT:
I found this work https://www.artima.com/cppsource/subscription_problem.html which addresses the object factory registration problem in the templated case.
However, the registration of the derived classes is still a responsibility of whoever knows the type(s) the derived class can be instantiated with.
Typically, the class developer does not have such a knowledge - the user does have it.
So, again, is there any method to dismiss the user from the responsibility of registering the derived class?

Related

std::function and friend function

In this example, I have a pointer of function (std::function) as an attribute of my class. So I can associate any function of the form void myFunction(void) to my class.
#include <iostream>
#include <functional>
class Example{
private:
int variable=4;
public:
std::function<void(void)> myNonMemberFunction;
Example(void){
}
Example(std::function<void(void)> MyNonMemberFunction){
myNonMemberFunction=MyNonMemberFunction;
}
};
void PrintPlop(){
std::cout<<"plop"<<std::endl;
}
int main() {
Example example(PrintPlop);
example.myNonMemberFunction();
}
Now, I want to do the same but with a function which has accessed to the class attribute like a friend function or a class-member function. How can I do this?
So you want any function you pass to the constructor become a friend?
In the strict sense it is impossible, because the access level (friend or not) is a compile-time issue, and which value is passed to the constructor, generally speaking, is determined only in run-time.
So you either declare all the relevant functions as friends (why not just make them methods in this case?) or pass the private members to them as additional parameters. Like this:
class Example{
private:
int variable=4;
std::function<void(int)> myNonMemberFunction;
public:
Example(void){
}
Example(std::function<void(int)> MyNonMemberFunction){
myNonMemberFunction=MyNonMemberFunction;
}
void callMyNonMemberFunction() {
myNonMemberFunction(variable);
}
};
void PrintPlop(int v){
std::cout<<"plop"<< v << std::endl;
}
int main() {
Example example(PrintPlop);
example.callMyNonMemberFunction();
}

creating a new derived type based on another class

I am trying to get a new derived class pointer (with new memory location) from a parent class pointer that points to a derived class.
#include <iostream>
#include <random>
class parent{
public:
virtual void print(){
printf("p\n");
}
};
class dev1: public parent{
public:
void print(){
printf("d1\n");
}
};
class dev2:public parent{
public:
void print(){
printf("d2\n");
}
};
int main(int argc, const char * argv[]) {
srand(time(NULL));
parent*bob;
if(rand()%2){
bob = new dev1();
}else{
bob = new dev2();
}
bob->print();
parent * bobwannabe;
bobwannabe = new typeof(*bob);
bobwannabe->print();
return 0;
}
I was hoping bobwannabe would print what bob prints. bobwannabe shouldn't point to the same object as bob but should be the same class as bob.
Right now, bobwannabe becomes a new parent. Is there a way to turn it into a new bob with it's current type or is there a specific term I should be searching up?
Thank you!
What you want is to clone the object. You need to do it yourself by adding a virtual clone method and copy constructor to the parent class:
virtual parent * clone() const { return new parent(*this); }
And override in all derived classes like for dev1:
virtual parent * clone() const override { return new dev1(*this); }
and use with:
parent *bobwannabe = bob->clone();
See also 'typeid' versus 'typeof' in C++ and don't forget to delete your objects or use smart pointers.

I am trying to use boost, C++ with templates, and factory pattern but can't seem to figure out the right syntax for it?

Here is the specifics:
Consider a simple constructor in a class with two input arguments,
concreteclass(_1, _2).
I have a map for this instantiation, map <string, concreteclassType>.
Also, these classes work with different datatypes concreteclass<double>(_1,_2) is different from concreteclass<int>(_1,_2).
Now that my problem is described above here is what I try to do using boost::factory pattern, classes defined in a string map and datatypes defined in an enum.
First, there is a simple way to demonstrate how boost factory pattern can be used with constructor arguments, the following nicely code works:
// Factory which takes two arguments
struct base {
base(int alpha) : alpha(alpha) {}
virtual ~base() = default;
virtual void print() const = 0;
int alpha;
};
struct derived : public base {
derived(int alpha, int beta) : base(alpha), beta(beta) {}
void print() const override {
std::cout << alpha << " " << beta << std::endl;
}
int beta;
};
void TestBoostFactoryWithTwoArgs()
{
// Constructor factory with two input args
{
std::map<std::string, boost::function<base* (int&, int&)>> factories;
factories["derived"] = boost::bind(boost::factory<derived*>(), _1, _2);
int x = 42;
int y = 51;
std::unique_ptr<base> b{ factories.at("derived")(x,y) };
b->print();
}
// Factory with two initialized inputs args - binding of values not at run time
{
std::map<std::string, boost::function<base* ()>> factories;
factories["derived"] = boost::bind(boost::factory<derived*>(), 42, 51);
std::unique_ptr<base> b{ factories.at("derived")() };
b->print();
}
}
Now consider my code - SimpleClasses.h:
// Dummy base class - non template
class IBaseClass
{
public:
};
// Templatized Derived Base class
template <typename T>
class ConcreteClass : public IBaseClass
{
private:
std::shared_ptr<IBaseClass> m_leftArgument;
std::shared_ptr<IBaseClass> m_leftArgument;
public:
ConcreteClass(std::unique_ptr<IBaseClass>& leftArgument, std::unique_ptr<IBaseClass>& rightArgument)
{
m_leftArgument = leftArgument;
m_rightArgument = rightArgument;
};
virtual T DoSomething()
{
cout << "I did something in Concrete Base Class" << endl;
return T();
}; // This is the main reason for creating T
};
template <typename T>
class ConcreteClassA : ConcreteClass
{
};
template <typename T>
class ConcreteClassB : ConcreteClass
{
};
template <typename T>
class ConcreteClassC : ConcreteClass
{
};
Another File, ClassFactory.h :
#pragma once
#include "SimpleClasses.h"
#include <memory>
#include <map>
#include <boost/functional/overloaded_function.hpp>
#include <boost/functional/factory.hpp>
using namespace std;
// Add More class Keys here
namespace MyClassesNamespace { // These are all string keys
static const string CLASS_A = "specialclassA";
static const string CLASS_B = "specialclassB";
static const string CLASS_C = "specialclassC";
};
enum EMyDataTypes
{
INT8,
FLOAT8,
FLOAT16,
};
// This type def we keep for non templatized base class constructor
typedef boost::function<IBaseClass*(std::unique_ptr<IBaseClass>&, std::unique_ptr<IBaseClass>&)> IBaseClassConstructorFunc_factory;
// Dummy base factory - no template
class UBaseClassTemplateFactory
{
public:
};
template<typename T>
class UClassFactoryTemplate : public UBaseClassTemplateFactory
{
private:
static std::map<string, IBaseClassConstructorFunc_factory> ClassFactoryTemplateMap; // Unique Classes only
public:
UClassFactoryTemplate();
__forceinline static UClassFactoryTemplate*Get()
{
static UClassFactoryTemplate<T> SingletonInstance;
return &SingletonInstance;
}
static std::unique_ptr<IBaseClass<T>> CreateClassTemplatized(string ClassString, std::unique_ptr<IBaseClass> LeftArgument, std::unique_ptr<IBaseClass> RightArgument);
};
// This type def we keep for non templatized base class
typedef boost::function<UBaseClassTemplateFactory*()> ClassFactoryTemplate_factory;
/* This is the instance class that resolves the classes as well as the concrete datatype to be used in UClassFactoryTemplate*/
class UClassFactory
{
private:
UClassFactory();
static std::map<EMyDataTypes, ClassFactoryTemplate_factory> ClassDataTypeTemplateFactoryMap;
public:
__forceinline static UClassFactory *Get()
{
static UClassFactory SingletonInstance;
return &SingletonInstance;
}
static std::unique_ptr<IBaseClass> CreateConcreteClass(string ClassString, std::unique_ptr<IBaseClass> LeftVal, std::unique_ptr<IBaseClass> RightVal, EMyDataTypes someEnumVal = EMyDataTypes::INT8);
};
Finally, in ClassFactory.cpp
#include "ClassFactory.h"
#include <boost/bind.hpp>
/*static, but non-const data members should be defined outside of the class definition
*and inside the namespace enclosing the class. The usual practice is to define it in
*the translation unit (*.cpp) because it is considered to be an implementation detail.
*Only static and const integral types can be declared and defined at the same time (inside class definition):*/
template<typename T>
std::map<string, IBaseClassConstructorFunc_factory> UClassFactoryTemplate<T>::ClassFactoryTemplateMap;
std::map<EMyDataTypes, ClassFactoryTemplate_factory> UClassFactory::ClassDataTypeTemplateFactoryMap;
template<typename T>
inline UClassFactoryTemplate<T>::UClassFactoryTemplate()
{
ClassFactoryTemplateMap[MyClassesNamespace::CLASS_A] = boost::bind(boost::factory<ConcreteClassA<T>*>(), _1, _2);
ClassFactoryTemplateMap[MyClassesNamespace::CLASS_B] = boost::bind(boost::factory<ConcreteClassB<T>*>(), _1, _2);
ClassFactoryTemplateMap[MyClassesNamespace::CLASS_C] = boost::bind(boost::factory<ConcreteClassC<T>*>(), _1, _2);
}
template<typename T>
std::unique_ptr<IBaseClass<T>> UClassFactoryTemplate<T>::CreateClassTemplatized(string ClassString, std::unique_ptr<IBaseClass> LeftArgument, std::unique_ptr<IBaseClass> RightArgument)
{
std::unique_ptr<IBaseClass<T>> someTemplatizedDataTypeInstance{ ClassFactoryTemplateMap.at(ClassString) (LeftArgument,RightArgument) };
return someTemplatizedDataTypeInstance;
}
UClassFactory::UClassFactory()
{
ClassDataTypeTemplateFactoryMap[EMyDataTypes::INT8] = boost::bind(boost::factory<UClassFactoryTemplate<int>*>());
ClassDataTypeTemplateFactoryMap[EMyDataTypes::FLOAT8] = boost::bind(boost::factory<UClassFactoryTemplate<float>*>());
ClassDataTypeTemplateFactoryMap[EMyDataTypes::FLOAT16] = boost::bind(boost::factory<UClassFactoryTemplate<double>*>());
}
std::unique_ptr<IBaseClass> UClassFactory::CreateConcreteClass(string ClassString, std::unique_ptr<IBaseClass> LeftVal, std::unique_ptr<IBaseClass> RightVal, EMyDataTypes someEnumVal)
{
std::unique_ptr<UBaseClassTemplateFactory> BaseOperatorTempFactory{ ClassDataTypeTemplateFactoryMap.at(someEnumVal) };
return BaseOperatorTempFactory->Get()::CreateClassTemplatized(ClassString, LeftVal, RightVal);
}
The question now is, the above code does not even compile let alone run, it says abstract class cannot be instantiated for the templatized map. I just want the UClassFactory to return me correct instantiated class like A,B,C based on a string map with correct datatypes based on an enum. How do I achieve this combination? I wonder what is the correct syntax? Or is my approach inherently flawed? Or there is a nice way to instantiate classes with factory pattern and different datatypes? Please let me know any suggestions/ comments.
Thanks
Alam

How to make a particular constructor on a tempate type available only for a particular specialization in C++11?

I have a C++11 template that can be specialized with an arbitrary type parameter.
template<class ElementType>
class Foo
How do I declare a constructor that appears for the compiler's consideration only when ElementType is e.g. const uint8_t?
That is, I have a bunch of constructors that are generic over any ElementType, but I also want to have constructors that are only considered when ElementType is specialized in a particular way. (Allowing those constructors to be selected for other types would be unsafe.)
So far std::enable_if examples that I've found have been conditional on the types of the arguments of the constructors.
template<class ElementType>
struct Foo
{
template <typename T = ElementType>
Foo(typename std::enable_if<!std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
template <typename T = ElementType>
Foo(typename std::enable_if<std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
};
int main()
{
Foo<int> a{}; // ok, calls first constructor
Foo<const uint8_t> b{}; // ok, calls second constructor
}
wandbox example
You can break the class into two classes. The derived class' purpose is to be able to specialize constructors for different types. E.g.:
#include <cstdio>
#include <cstdint>
template<class ElementType>
struct Foo_
{
Foo_() { std::printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class ElementType>
struct Foo : Foo_<ElementType>
{
using Foo_<ElementType>::Foo_; // Generic version.
};
template<>
struct Foo<uint8_t> : Foo_<uint8_t>
{
Foo() { std::printf("%s\n", __PRETTY_FUNCTION__); } // Specialization for uint8_t.
};
int main(int ac, char**) {
Foo<int8_t> a;
Foo<uint8_t> b;
}
The benefit of using the derived class here compared to enable_if is that:
The class can be partially specialized.
Only one specialization of the class is chosen for particular template parameters, rather than a set of constructors. When adding specializations for new types the existing enable_if expressions may need to be changed to make them more restrictive to avoid function overload set resolution ambiguity.

c++11 template metaprogramming construct a std::unorderer_map at compile time

i trying to develop a Finite State Machine with template meta programming techniques, but i getting stuck with a map that it has to be fill at compile time, this the code(gcc 4.8 c++11):
#include <functional>
#include <type_traits>
#include <iostream>
#include <unordered_map>
namespace NSStateMachine {
//Definicion de estado unidad
template<class FSM, class From, class Event, class TO, bool(FSM::* transicion_fn)(const Event &)>
struct Transition
{
using FSM_TYPE=FSM;
using FROM_STATE= From;
using EVENT_TYPE= Event;
using TO_STATE_TYPE=TO;
using EVENT_BASE_TYPE = typename Event::BASE_TYPE;
static bool do_transition(FSM_TYPE& currenState, EVENT_BASE_TYPE const& aEvent)
{
return (currenState.*transicion_fn)(static_cast<EVENT_TYPE const&>(aEvent));
}
};
//States
template<class Transition, const Transition * const TransitionPtr, class ... Args>
class StateMachine
{
public:
StateMachine():transitionMap{{static_cast<typename Transition::TransitionID>(*TransitionPtr::TransitionID_Value),nullptr}}
{}
template<class Event>
bool evalEvent(const Event & aEvent)
{
std::cout<<"evento recibido"<<std::endl;
}
std::unordered_map<typename Transition::TransitionID, const Transition * const > transitionMap ;
};
}
int main()
{
//it doesnt compile, i canoot create the state machine
return 0;
}
The compile error:
error: 'TransitionPtr' is not a class, namespace, or enumeration
StateMachine():transitionMap{{static_cast<typename Transition::TransitionID>(*TransitionPtr::TransitionID_Value),nullptr}}
^
The problem seem to be in the line
transitionMap{{static_cast<typename Transition::TransitionID>(*TransitionPtr::TransitionID_Value),nullptr}}
i will try to init the unorderer_map with the automatic constructor.
i have defined this Transition::TransitionID as a class variable defined in the class represented by the template argument
I will really appreciate any help.
Thx!!!!
i have already test with default types , it compile and work this
The error message is pretty clear. TransitionPtr is a pointer, not a type, so you can't use it to the left of :: in TransitionPtr::TransitionID_Value.
Also, I don't think you'll find a way to initialize an unordered_set at compile time, since it doesn't have constexpr constructors and in general almost certainly uses heap allocations.

Resources