Clear heavy use of template options

I have a set of classes in the logging structure used in projects A and B. I refactor the structure, so it can be used in projects B and C. Refactoring basically consists of providing all the template parameters: project A can run on an embedded device with poor / missing STL execution, while B and C run only on the PC, but B is single-threaded, and C uses multithreading.

This works well, but leads to what seems like a huge amount of template parameters to me and a pretty ugly typedef mess. I need 20 lines to typedef all the classes that I am going to use, and there are also many classes that accept a template parameter that they do not use themselves, but it is necessary to be able to typedef another class that they use (which is not bad in itself, but in the end, everything starts to get very complicated). Another problem is that when I want to add some functionality to class A, and this requires adding a container, class A needs an additional template template. As a result, all other classes that see / use class A suddenly also need an additional parameter leading to a domino effect.

A slightly exaggerated example:

template< class string, class map, class mutex >
class MessageDestination
{
  typedef Message< string, map > message_type;
  virtual void Eat( const message_type& ) = 0;
}

template< class string, class map, class stream >
class MessageFormatter
{
  typedef Message< string, map > message_type;
  virtual void Format( const message_type&, stream& ) = 0;
}

template< class string, class map, class containerA,
          template< class, class > containerB, template< class, class > class queue, class allocator >
class ThreadedMessageAcceptor
{
  typedef Message< string, map > message_type;
  typedef MessageDestination< string, map > destination_type;
  typedef containerB< destination_type, allocator > destinations_type;
  typedef queue< message_type, allocator > messages_type;
};

I can come up with some methods to clear this, but it's hard for me to decide which one or which combination to use. StackOverFlow, your help will be appreciated!

Here is the first solution I was thinking of combining the parameters into a type that they will eventually form:

template< class message, class mutex >
class MessageDestination
{
  virtual void Eat( const message& ) = 0;
}

It simplifies, but isn't it something that actually hides what message? Suppose that the user wants to provide an implementation, he does not directly see that this message should use a certain type of string, etc.

Another technique that I talked about, but I don’t remember, to see that I saw something that causes suspicion, simply defines everything in one structure and passes it as the only template parameter to everything:

struct MyTemplateParameters
{
  typedef std::string string;
  typedef std::map map;
  typedef std::queue queue;
  typedef LightMutex mutex;
  template< class A, class B >
  struct DefineContainerB
  {
    typedef containerB< A, B >::type;
  }
  //....
};

template< class parameters >
class MessageDestination
{
  typedef Message< parameters > message_type;
  virtual void Eat( const message_type& ) = 0;
};

template< class parameters >
class ThreadedMessageAcceptor
{
  typedef Message< parameters > message_type;
  typedef MessageDestination< parameters > destination_type;
  typedef parameters::DefineContainerB< destination_type, parameters::allocator >::type destinations_type;
};

, , typedefs - XXX <MyTemplateParameters> , . ?

+3
1

"" ++. < ".

( ?). Boost ++. , . std::basic_string.


- . "", , . , , "" :

template <typename T>
struct identity {
    typedef T type;
};

Metafunction ( "" ), .

typedef identity<int>::type mytype; // or
identity<int>::type x;

. :

template <typename T>
struct remove_const {
    typedef T type;
};

template <typename T>
struct remove_const<T const> {
    typedef T type;
};

, ( , ) . Im, : , const, . , . , :

typename remove_const<T>::type& _reference;

( typename, T remove_const<T>::type . typename - !)

, ?

, , :

struct Embedded { };
struct Compliant { };

, :

template<typename Spec>
class ThreadedMessageAcceptor
{
    typedef Message< Spec > message_type;
    typedef MessageDestination< Spec > destination_type;
    typedef typename Allocator< destination_type, Spec >::type allocator_type;
    typedef typename ContainerB< destination_type, allocator_type, Spec >::type destinations_type;
};

Spec Compliant, Embedded. , , :

ThreadedMessageAcceptor<Compliant> x;

:

template <typename T, typename Spec>
struct Allocator { };

template <typename T, typename Alloc, typename Spec>
struct ContainerB { };

, , :

template <typename T>
struct Allocator<T, Compliant> {
   typedef std::allocator<T> type;
};

template <typename T, typename Alloc>
struct ContainerB<T, Alloc, Compliant> {
    typedef std::vector<T, Alloc> type;
};

, , Spec ( Ive , ).

, , , , .

+5

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


All Articles