Flow123d  release_2.2.0-37-g336ee74
factory.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file factory.hh
15  * @brief
16  */
17 
18 #ifndef FIELD_RECORD_FACTORY_HH_
19 #define FIELD_RECORD_FACTORY_HH_
20 
21 #include <memory>
22 #include <string>
23 #include <map>
24 #include <functional>
25 #include <boost/functional/factory.hpp>
26 #include <boost/any.hpp>
27 
28 #include "system/exceptions.hh"
29 
30 
31 namespace Input {
32 
33 using namespace std;
34 
35 
36 TYPEDEF_ERR_INFO( EI_KeyName, const string);
37 TYPEDEF_ERR_INFO( EI_TypeName, const string);
38 DECLARE_EXCEPTION( ExcNotRegistredClass, << "Key " << EI_KeyName::val
39  << " isn't registered in factory for type " << EI_TypeName::val << "!");
40 
41 
42 /**
43  * @brief This class implements more general factory mechanism to construct classes.
44  *
45  * One factory allows constructing derived classes of one base class. This class is determined
46  * by template parameter Type and all descendants must implement constructor with same
47  * parameters (given by template parameter Arguments). This constructor is called by factory.
48  *
49  * All descendants must contain:
50  * 1. constructor with parameters given by Arguments
51  * 2. declaration of parent class as typedef with name FactoryBaseType
52  * 3. private static integer variable what is only for registration class to factory, this variable only allow
53  * to register class to factory and its implementation must call:
54  * (a) Factory::register_class that adds constructor of class to factory
55  * (b) generating function of Input::Type::Record (usually get_input_type() method)
56  *
57  * Simple example of usage:
58  @code
59  class SomeDescendant : public SomeBase
60  {
61  public:
62  /// typedef of parent class
63  typedef SomeBase FactoryBaseType;
64 
65  /// Return initialization Record
66  static const Input::Type::Record & get_input_type();
67 
68  /// constructor
69  SomeDescendant() {}
70 
71  private:
72  /// registers class to factory
73  static const int reg;
74  }
75 
76  /// implementation of registration variable
77  const int SomeDescendant::reg =
78  Input::register_class< SomeDescendant >("SomeDescendant") +
79  SomeDescendant::get_input_type().size();
80  @endcode
81  *
82  * Factory allow to accept constructor with one or more parameters. In this case Factory is
83  * also templated by these parameters. For example Factory< SomeBase, int, double > accepts
84  * constructors with two parameters (int, double).
85  *
86  * If registered class is templated the following design have to be used:
87  @code
88  /// Example of class templated by integer parameter
89  template <int dimension>
90  class SomeDescendant : public SomeBase<dimension>
91  {
92  public:
93 
94  /// constructor
95  SomeDescendant(double time) {}
96  ...
97  }
98 
99  /// implementation of registration variable
100  const int SomeDescendant::reg =
101  Input::register_class< SomeDescendant<dimension>, double >("SomeDescendant") +
102  SomeDescendant<dimension>::get_input_type().size();
103  @endcode
104  *
105  * Factory can be used in two ways:
106  * - through Factory::create method
107  * Example for constructor with one parameter:
108  @code
109  SomeBase * sb = Input::Factory< SomeBase, double >::instance()->create("SomeDescendant", 0.1);
110  @endcode
111  * - through AbstractRecord::factory method. This possibility can be used if base class has defined
112  * AbstractRecord and its descendants contain Record derived from this AbstractRecord.
113  * Example for same constructor:
114  @code
115  AbstractRecord a_rec = record.val<AbstractRecord>("problem");
116  SomeBase * sb = a_rec.factory< SomeBase, double>(0.25);
117  // If arguments types can be deduced (by compiler) from actual arguments one can even use:
118  SomeBase * sb = a_rec.factory< SomeBase >(0.25);
119  @endcode
120  *
121  * For correct functionality must be used two macros defined in global_defs.h:
122  * - FLOW123D_FORCE_LINK_IN_CHILD(x)
123  * - FLOW123D_FORCE_LINK_IN_PARENT(x)
124  * First is used in C source file of descendant class out of class methods, e.g.:
125  * FLOW123D_FORCE_LINK_IN_CHILD(gmsh)
126  * Second is used in C source file of parent class in any of class method with same parameter as in
127  * first used, e.g.:
128  * FLOW123D_FORCE_LINK_IN_PARENT(gmsh)
129  *
130  */
131 template <class Type, class... Arguments>
132 class Factory
133 {
134 public:
135  /// Get the single instance of the factory
136  static Factory * instance();
137 
138 
139  /// Register lambda function that calls default constructor of Type.
140  template <class Child>
141  static int register_class(string class_name);
142 
143 
144  /// create an instance of a registered class
145  shared_ptr<Type> const create(string name, Arguments... arguments) const;
146 
147 
148 private:
149  /// Forbid default constructor
151 
152  /// the registry of factory functions
154 
155 };
156 
157 
158 /**
159  * @brief Function allows simplified call of registering class to factory.
160  *
161  * It is used for declaration of registration variable.
162  * @see Factory
163  *
164  * Example of usage:
165  @code
166  const int SomeClass::reg =
167  Input::register_class< SomeClass >("SomeClass");
168  @endcode
169  */
170 template <class ChildType, class... Arguments>
171 int register_class(string class_name);
172 
173 
174 } // closing namespace Input
175 
176 // include implementation of templates and inline methods
177 #include "factory_impl.hh"
178 
179 #endif // FIELD_RECORD_FACTORY_HH_
DECLARE_EXCEPTION(ExcTypeMismatch,<< "Key:"<< EI_KeyName::qval<< ". Can not construct Iterator<T> with C++ type T="<< EI_CPPRequiredType::qval<< ";\n"<< "can not convert Type: "<< EI_InputType::qval<< " to: "<< EI_RequiredType::qval)
map< string, boost::any > factory_registry_
the registry of factory functions
Definition: factory.hh:153
int register_class(string class_name)
Function allows simplified call of registering class to factory.
Definition: factory_impl.hh:64
Factory()
Forbid default constructor.
Definition: factory.hh:150
TYPEDEF_ERR_INFO(EI_InputType, const string)
This class implements more general factory mechanism to construct classes.
Definition: factory.hh:132