Search code examples
c++templatesc++14virtual-functionsdynamic-dispatch

Alternative to virtual templates


I have a class storing a fixed size amount of data

template<size_t SIZE> class Data {...};

Now I have different algorithms for generating data (e.g. pseudorandom generators):

class PseudoRandom1 {
   template<size_t SIZE> Data<SIZE> generate();
};

class PseudoRandom2 {
   template<size_t SIZE> Data<SIZE> generate();
};

Now I want to have a dynamic runtime decision as to which of these generators to call. Using virtual templates (which, I know, is not possible), it would be the following:

class Generator {
  virtual template<size_t SIZE> Data<SIZE> generate() = 0;
};

class PseudoRandomX : public Generator {
  template<size_t SIZE> Data<SIZE> generate() override {...}
};

Unfortunately, I cannot change the SIZE parameter of the data class to be a non-template runtime parameter. Furthermore, I need the actual generator instance to be a runtime decision, because the user can choose a generator algorithm. If possible, I'd prefer a typesafe solution (i.e. no boost::any).

I know virtual templates are not possible. Is there another way to solve this?


Solution

  • The following variation will work for at least some purposes consistent with the information you've given so far.

    class Generator {
    public:
        template< size_t SIZE >
        Data<SIZE> generate() {
            Data<SIZE> x;
            vgenerate(SIZE, x.pointer_to_internals());
            return x;
        }
    protected:
        virtual void vgenerate(size_t size, InternalDataPointer *p) = 0;
    };
    
    class PseudoRandomX : public Generator {
        void vgenerate(size_t size, InternalDataPointer *p) override {...}
    };
    

    Another solution that will work for a different set of purposes is

    template< size_t SIZE >
    class Generator {
    public:
        virtual Data<SIZE> generate() = 0;
    };
    
    template< size_t SIZE >
    class PseudoRandomX : public Generator<SIZE> {
        Data<SIZE> generate() override {...}
    };