Automatically instantiate multiple types in C ++

There are several “plugins” in our library that are implemented in their own cpp files. Each plugin defines a template function and must instantiate this function over a whole set of types. The number of types can be quite large, 30-100 of them and can vary depending on some parameters of the compilation time. Each instance really needs to be compiled and optimized individually, productivity increases 10-100 times. The question is what is the best way to create all these functions.

Each plugin is written by a scientist who actually does not know C ++, so the code inside each plugin must be hidden inside macros or some simple construction. I have a semi-baked solution based on a "database" of instances:

template<int plugin_id, class T>
struct S
{
   typedef T (*ftype)(T);
   ftype fp; 
};
// By default we don't have any instances
template<int plugin_id, class T> S::ftype S::fp = 0;

Now the user who wants to use the plugin can check the value

S<SOME_PLUGIN,double>::fp

to see if there is a double type version of this plugin. The fp template implementation will create a weak link, so the linker will use the “real” instance if we define it in the plugin implementation file. Inside the SOME_PLUGIN implementation, we will have an instance

template<> S<SOME_PLUGIN,double>::ftype S<SOME_PLUGIN,double>::fp = 
       some_plugin_implementation;

. , . . -, . , , , . , ( ).

+3
3

Boost.MPL, , . .

0

, , , , , S, ftype, , , , ... ie

template<int plugin_id, class T>
struct S
{
   typedef T (*ftype)(T);
   static ftype& instance()
   {
     static ftype _fp = T::create();
     return _fp;
   }
};

S<SOME_PLUGIN,double>::fp S<SOME_PLUGIN,double>::instance(). , - S<>::instance(). , ?

EDIT: , , ftype, . factory T, create(), .

EDIT: , , .. , ( ) , . , ... , ...

#include <iostream>
#include <typeinfo>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/algorithm.hpp>


using namespace std;

// This simply calls the static instantiate function
struct instantiate
{
  template <typename T>
  void operator()(T const& x) const
  {
    T::instance();
  }
};

// Shared header, presumably all plugin developers will use this header?
template<int plugin_id, class T>
struct S
{
  typedef T (*ftype)(T);

  static ftype& instance()
  {
    cout << "S: " << typeid(S<plugin_id, T>).name() << endl;
    static ftype _fp; // = T::create();
    return _fp;
  }
};

// This is an additional struct, each plugin developer will have to implement
// one of these...
template <int plugin_id>
struct S_Types
{
  // All they have to do is add the types that they will support to this vector
  static void instance()
  {
    boost::fusion::vector<
      S<plugin_id, double>,
      S<plugin_id, int>,
      S<plugin_id, char>
    > supported_types;
    boost::fusion::for_each(supported_types, instantiate());
  }
};

// This is a global register, so once a plugin has been developed,
// add it to this list. 
struct S_Register
{
  S_Register()
  {
    // Add each plugin here, you'll only have to do this when a new plugin
    // is created, unfortunately you have to do it manually, can't
    // think of a way of adding a type at compile time...
    boost::fusion::vector<
      S_Types<0>,
      S_Types<1>,
      S_Types<2>
    > plugins;
    boost::fusion::for_each(plugins, instantiate());
  }
};

int main(void)
{
  // single instance of the register, defining this here, effectively
  // triggers calls to instanc() of all the plugins and supported types...
  S_Register reg; 

  return 0;
}

The merge vector is mainly used to identify all possible instances that may exist. It will take a bit of work from you and the developers, as I stated in the code ... I hope this gives you an idea ...

0
source

Source: https://habr.com/ru/post/1773606/


All Articles