Alright, first things first, I will be providing the code I am asking my question for.
#ifndef EX_FACTORY_H
#define EX_FACTORY_H
#include <string>
#include <map>
#include "Base.h"
struct EX_Factory{
template<class U, typename... Args>
static void registerC(const std::string &name){
registry<Args...>[name] = &create<U>;
}
template<typename... Args>
static Base * createObject(const std::string &key, Args... args){
auto it = registry<Args...>.find(key);
if(it == registry<Args...>.end()) return nullptr;
return it->second(args...);
}
private:
EX_Factory() = delete;
template<typename... Args>
static std::map<std::string, Base*(*)(Args...)> registry;
template<class U, typename... Args>
static Base* create(Args... args){
return new U(args...);
}
};
template<typename... Args>
std::map<std::string, Base*(*)(Args...)> EX_Factory::registry;
template<typename U, typename... Args>
struct MiddleMan{
MiddleMan(const std::string &name){
EX_Factory::registerC<U,Args...>(name);
}
};
#define REGISTER_MACRO(NAME, TYPE, ...)\ // Updated the macro here
static MiddleMan<TYPE, ##__VA_ARGS__> mm_##TYPE(#NAME);
#endif
The code above is a header file for my Factory Design Pattern class. It allows the user of this class to register constructors for objects derived from the Base class with varying arguments.
Alright, quick explanation for why I am using __VA_ARGS__ vs ##__VA_ARGS__, the reason for this is, there will always be at least 1 argument, the template type U in the registerC template function, passed into the macro.
What I am trying to do is construct a preprocessor macro, REGISTER_MACRO , to register derived classes before runtime. How do I call a Variadic Template Function from a Variadic Macro correctly?
#include "EX_Factory_1.h"
#include <iostream>
using namespace std;
struct derived_1 : public Base{
derived_1(int i, int j, float f){
cout << "Derived 1:\t" << i * j + f << endl;
}
};
REGISTER_MACRO(name_1, derived_1, int,int,float);
struct derived_2 : public Base{
derived_2(int i, int j){
cout << "Derived 2:\t" << i + j << endl;
}
};
REGISTER_MACRO(name_2, derived_2, int,int);
int main(){ // Program segfaults before entering main
derived_1 * d_1 = static_cast<derived_1*>(EX_Factory::createObject<int, int, float>("name_1", 8, 8, 3.0));
if(d_1 == nullptr) cout << "Why is it null?" << endl;
else{
delete d_1;
}
return 0;
}
The errors I am receiving from trying to compile the above code: See Edit below
In file included from test.cpp:1:0:
EX_Factory.h:39:38: error: expected constructor, destructor, or type conversion before ‘(’ token
EX_Factory::registerC<__VA_ARGS__>(NAME);
^
test.cpp:11:1: note: in expansion of macro ‘REGISTER_MACRO’
REGISTER_MACRO("derived_1",derived_1,int,int,float)
^~~~~~~~~~~~~~
EX_Factory.h:39:38: error: expected constructor, destructor, or type conversion before ‘(’ token
EX_Factory::registerC<__VA_ARGS__>(NAME);
^
test.cpp:17:1: note: in expansion of macro ‘REGISTER_MACRO’
REGISTER_MACRO("derived_2",derived_2,int,int)
I am using the g++ 6.3 compiler, so by default, it compiles with C++14 standards in an Ubuntu 16.04 environment.
Potential solutions I've found, but don't fit my problem:
Is there a way to define variadic template macro
Using variadic macros or templates to implement a set of functions
Potential Solution but could not interpret its solution:
How to use variadic template with variadic macro ? I'm not using QT, and I am using a fully supported C++11 compiler.
I now know why my file will not compile, but I do not know how to handle creating an object to call the method for myself. I added a middle man class, MiddleMan, and added a call to the static registerC class to its constructor and modified my macro to create static references to this class. This allows my program to compile, but it segfaults with this method. You will see the mentioned reflections above now.
I am testing this class and macro out with my main.cpp in my answer to this question.
Alright, with the help from @rici , a little research, and the prior mention for the reason from @T.C. I developed a modified design which uses a Registrator object to register Derived Objects of Base into my Factory design.
To bypass the segfaults I was experiencing, I decided to implement Functors to store my template create functions. I designed a base functor, F, and a template derived functor, DF.
I created a getMap() method which returned the reference to a static map object which stored std::string and base functor pointer,F*, pairs in it.
My Solution's Code Below!
#ifndef FUNCTOR_FACTORY_H
#define FUNCTOR_FACTORY_H
#include <map>
#include <string>
#include "Base.h"
struct FunctorFactory{
private:
class F{ // Base Functor
public:
virtual ~F(){}
};
template<typename R, typename... A>
struct DF : public F{ // Templated Derived Functors
DF(R (*f)(A...)); // Regular Constructor
DF(const DF<R,A...>& df); // Copy Constructor
virtual ~DF(); // Virtual Destructor
virtual R operator()(A... args); // Overloaded () to allow function like use.
virtual DF<R,A...>& operator=(const DF<R,A...>& df); // Overloaded = to allow assignment
private:
R (*_f)(A...); // The actual function being called
};
static std::map<std::string,F*>& getMap(); // Map pairing string keys to their Functors(stored as Base Functors)
template<typename U, typename... A> // Templated create function which will create the derived objects being requested!
static Base * create(A... args);
public:
template<typename U, typename... A> // Registrator class which registers objects
struct Registrator{
Registrator(const std::string &key);
};
template<typename... A> // createObject static method which creates the requested object
static Base * createObject(const std::string &skey, A... args);
};
// Implementation of the derived functor's methods
template<typename R, typename... A> // Basic Constructor.
FunctorFactory::DF<R,A...>::DF(R (*f)(A...)){_f = f;}
template<typename R, typename... A> // Copy Constructor.
FunctorFactory::DF<R,A...>::DF(const FunctorFactory::DF<R,A...>& df){_f = df._f;}
template<typename R, typename... A> // Destructor
FunctorFactory::DF<R,A...>::~DF(){}
template<typename R, typename... A> // Overloaded () operator
R FunctorFactory::DF<R,A...>::operator()(A... args){return _f(args...);}
template<typename R, typename... A> // Overloaded = operator
FunctorFactory::DF<R,A...>& FunctorFactory::DF<R,A...>::operator=(const FunctorFactory::DF<R,A...>& df){_f = df._f;}
std::map<std::string,FunctorFactory::F*>& FunctorFactory::getMap(){ // Get map class
static std::map<std::string,FunctorFactory::F*> m_map; // The actual map storing the functors.
return m_map;
}
template<typename U, typename... A>
Base * FunctorFactory::create(A... args){
return new U(args...);
}
template<typename U, typename... A>
FunctorFactory::Registrator<U,A...>::Registrator(const std::string &key){
DF<Base*,A...> * df = new DF<Base*,A...>(FunctorFactory::create<U,A...>);
getMap()[key] = df;
}
template<typename... A>
Base * FunctorFactory::createObject(const std::string &skey, A... args){
auto it = getMap().find(skey);
if(it == getMap().end()) return nullptr;
DF<Base*,A...> * df = static_cast<DF<Base*,A...>*>(it->second);
return (*df)(args...);
}
#ifndef FF_MACRO
#define FF_MACRO(NAME,TYPE,...)\
namespace { \
::FunctorFactory::Registrator<TYPE,##__VA_ARGS__> registrator_##NAME(#NAME); \
}
#endif
#endif // FUNCTOR_FACTORY_H
#ifndef BASE_H
#define BASE_H
class Base{
public:
virtual ~Base(){}
};
#endif
#include "FunctorFactory.h"
#include <iostream>
using namespace std;
struct derived_1 : public Base{
derived_1(int i, int j, float f){
cout << "Derived 1:\t" << i * j + f << endl;
}
};
FF_MACRO(name_1, derived_1, int,int,float);
struct derived_2 : public Base{
derived_2(int i, int j){
cout << "Derived 2:\t" << i + j << endl;
}
};
FF_MACRO(name_2, derived_2, int,int);
int main(){
derived_1 * d_1 = static_cast<derived_1*>(FunctorFactory::createObject<int, int, float>("name_1", 8, 8, 3.0));
if(d_1 == nullptr) cout << "The function being requested must either have different parameters or a different key." << endl;
else{
delete d_1;
}
return 0;
}
Derived 1: 67
I hope this helps anyone who comes across a similar problem to this. Feel free to use this Factory Model as well if you need to. It is able to store multiple different mappings for overloaded constructors to the same object type as well as multiple different derived objects.