vendredi 24 avril 2015

C++ Partial template specialization - design simplification

I am working on a pipeline/dataflow design patter for a specific application area. I have an 'algorithm data output' class (AlgorithmOutput) which serves as an interface between two connected network elements. In particular, it provides a set of templated getOutput<size_t N> methods which are used for the data output from a 'data transmitter' object.

The current design is based on the idea that users derive from AlgorithmOutput class and provide a finite number of implementations ofgetOutput<size_t N> methods. I also need to be able to allow the users to provide their own custom return types from the getOutput methods (i.e. the return type cannot be polymorphic). Moreover, it is necessary to have all getOutput implementations to be able to access the same data set (e.g. defined in a particular class).

The current solution is to use partial explicit specialisation in the classes derived by the user to define the different implementations of the getOutput method. While this works well, it is simply overly complex. I would like to simplify it and would appreciate any ideas on how this can be done without loosing the functionality of the design.

EDIT: I am only concerned about the ease of implementation of additional implementations of the getOutput method from the user side. I am not too much concerned about how complex is the implementation of the base classes. Thus, the mechanism for the definition of implementations of getOutputImpl structures could be an 'add-on' to the PipeOutputClass.

An example implementation of the derived class:

class PipeOutputClass: public AlgorithmOutput<PipeOutputClass>
{

public:

    template <size_t N>
    auto getOutput(size_t c_Idx) const
        {
            return getOutputImpl<N>::apply(this, c_Idx);
        }

    template<size_t N, typename S> friend struct getOutputImpl;

    template<size_t N, typename = void>
    struct getOutputImpl
    {
        static auto apply(
            PipeOutputClass const* p_Self,
            size_t c_Idx
            )
            {
                throw std::runtime_error("Wrong template argument.");
            }
    };

    template <typename S>
    struct getOutputImpl<0, S>
    {
        static std::unique_ptr<double> apply(
            PipeOutputClass const* p_Self,
            size_t c_Idx
            )
            {
                std::unique_ptr<double> mydouble(new double(10));
                return mydouble;
            }
    };

    template <typename S>
    struct getOutputImpl<1, S>
    {
        static std::unique_ptr<int> apply(
            PipeOutputClass const* p_Self,
            size_t c_Idx
            )
            {
                std::unique_ptr<int> myint(new int(3));
                return myint;
            }
    };

};

Aucun commentaire:

Enregistrer un commentaire