Compile-time type based dispatch

Following strategies from 'Modern C+npls Design', I am applying a perseverance collection with numerous compile - time optimizations. I would certainly such as the capacity to send off a function to a templated member variable if that variable stems from an offered class:

template<class T, template <class> class Manager = DefaultManager> class Data
{
private:
   T *data_;

public:
   void Dispatch()
   {
      if(SUPERSUBCLASS(Container, T))
      {
         data_->IKnowThisIsHere();
      }
      else
      {
         Manager<T>::SomeGenericFunction(data_);
      }
   }
}

Where SUPERSUBCLASS is a compile - time macro to establish object inheritance. Certainly, this falls short in all instances where T does to acquire from Container (or T is an inherent type etc etc) due to the fact that the compiler appropriately whines that IKnowThisIsHere() is not an information participant, despite the fact that this code course will certainly never ever be adhered to, as revealed below after preprocessing with T = int:

private:
   int *data_;

public:
   void Dispatch()
   {
      if(false)
      {
         data_->IKnowThisIsHere();

Compiler plainly whines at this code, despite the fact that it will certainly never ever get implemented. A pointer of making use of a dynamic_cast additionally does not function, as once more a type conversion is tried at compile time that is not feasible (as an example with T = double, sexually transmitted disease:: string) :

void Dispatch()
   {
      if(false)
      {
         dynamic_cast<Container*>(data_)->IKnowThisIsHere();

error: cannot dynamic_cast '((const Data<double, DefaultManager>*)this)->Data<double, DefaultManager>::data_' (of type 'double* const') to type 'class Container*' (source is not a pointer to class)
error: cannot dynamic_cast '((const Data<std::string, DefaultManager>*)this)->Da<sttad::string, DefaultManager>::data_' (of type 'struct std::string* const') to type 'class Container*' (source type is not polymorphic)

I actually require to mimic (or without a doubt encourage!) having the compiler send out one set of code if T does acquire from Container, and also an additional if it does not.

Any kind of pointers?

5
2022-07-25 20:42:09
Source Share
Answers: 2

Overloading can be valuable to implement compile - time sending off, as recommended by Alexandrescu in his publication "Modern C+npls Design".

You can make use of a class similar to this to change at compile time a boolean or integer right into a type:

template <bool n>
struct int2type
{ enum { value = n}; };

The adhering to resource code reveals a feasible application:

#include <iostream>

#define MACRO()   true  // <- macro used to dispatch 

template <bool n>
struct int2type
{ enum { value = n }; };

void method(int2type<false>)
{ std::cout << __PRETTY_FUNCTION__  << std::endl; }

void method(int2type<true>)
{ std::cout << __PRETTY_FUNCTION__  << std::endl; }

int
main(int argc, char *argv[])
{
    // MACRO() determines which function to call
    //

    method( int2type<MACRO()>()); 

    return 0;
}

Of training course what actually makes the work is the MACRO() or a far better execution as a metafunction

3
2022-07-25 22:04:54
Source

You require a kind of compile-time if. This then calls a function depending on which case is true. This way, the compiler won't stumble upon code which it can't compile (because that is safely stored away in another function template that never gets instantiated).

There are several ways of realizing such a compile-time if. The most common is to employ the SFINAE idiom: . Boost's is_base_of ist actually an instance of this idiom. To employ it correctly, you wouldn't write it in an if expression but rather use it as the return type of your function.

Untested code:

void Dispatch()
{
    myfunc(data_);
}

private:

// EDIT: disabled the default case where the specialisation matched
template <typename U>
typename enable_if_c<is_base_of<Container, U>::value, U>::type myfunc(U& data_) {
    data_->IKnowThisIsHere();
}

template <typename U>
typename disable_if_c<is_base_of<Container, U>::value, U>::type myfunc(U& data_) { // default case
    Manager<U>::SomeGenericFunction(data_);
}
2
2022-07-25 20:48:16
Source