x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

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

Although this is a C++ question, I am trying to use this with unreal engine ot create my own classes. Here is the specifics:

  1. Consider a simple constructor in a class with two input arguments, concreteclass(_1, _2).

  2. I have a map for this instantiation, map ``.

  3. Also, these classes work with different datatypes concreteclass(_1,_2) is different from concreteclass(_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 code nicely 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

Product Version: UE 4.15
Tags:
more ▼

asked May 20 '17 at 08:06 PM in C++ Programming

avatar image

Infiltrator_
13 3 9 12

(comments are locked)
10|2000 characters needed characters left

0 answers: sort voted first
Be the first one to answer this question
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question