jeudi 27 octobre 2016

C++: Generic function wrapper class as a member of a non-template class

I am trying to implement a Kalman filter class that can accept a user provided measurement model function, which can have any number of parameters. If your not familiar with Kalman filters it doesn't matter, basically I have a non-template class that has a templated constructor that receives a function with any number of parameters of any type. The constructor then assigns the passed function to a function wrapper member object, which itself is constructed based on variadic template classes. The problem I am having is how do I declare the function wrapper object as a member of my Kalman filter class without knowing the specific form of the function that will be passed to the constructor?

I apologise if this is not very clear. However, I have basically been following this answer to this question, where the line auto add = make_action([] (int a, int b) { std::cout << a + b; }, 2, 3) represents the functionality that I want to incorporate into my non-template class as a member variable (with the assignment taking place in the constructor).

Here is my code:

    #include <iostream>
    #include <functional>
    #include <tuple>

    namespace Helper
    {

        template <std::size_t... Ts>
        struct Index {};

        template <std::size_t N, std::size_t... Ts>
        struct GenSeq : GenSeq<N-1, N-1, Ts...> {};

        template <std::size_t... Ts>
        struct GenSeq<0, Ts...> : Index<Ts...> {};

    }


    template <typename... ArgTps>
    class MeasModWrapper
    {

        private:

            std::function<void(ArgTps...)> MeasMod;
            std::tuple<ArgTps...> MeasModArgs;


        public:


            template <typename MsModFnc, typename... ArgTs>
            MeasModWrapper( MsModFnc&& MsMod, ArgTs&&... args ) 
                :    MeasMod( std::forward<MsModFnc>(MsMod) ), 
                     MeasModArgs( std::make_tuple( std::forward<ArgTs>(args)... ) )
            {}

            template <typename... ArgTs, std::size_t... Is>
            void MsMod( std::tuple<ArgTs...>& tup, Helper::Index<Is...> )
            {
                MeasMod( std::get<Is>(tup)... );
            }

            template <typename... ArgTs>
            void MsMod( std::tuple<ArgTs...>& tup )
            {
                MsMod( tup, Helper::GenSeq<sizeof...(ArgTs)>{} );
            }




            void CallMeasMod( void )
            {
                MsMod( MeasModArgs );
            }

    };


    template <typename MsModFnc, typename... ArgTs>
    MeasModWrapper<ArgTs...> BindMeasMod( MsModFnc&& MsMod, ArgTs&&... args )
    {

        return MeasModWrapper<ArgTs...>( std::forward<MsModFnc>( MsMod ), std::forward<ArgTs>( args )... );

    }


    // The following is where my code differs from the solution provided by user 0x499602D2 (many thanks btw)
    class KF
    {

        private:

            auto measurementModel;              // <--- This doesn't work, and I expected that it wouldn't, but how can I get around this problem???


        public:

            template <typename MsFnc, typename... FncArgs>
            KF( MsFnc&& msFnc, FncArgs&&... fncArgs )
                :    measurementModel( BindMeasMod( msFnc ), std::forward<FncArgs>( fncArgs )... )
            { }

            void CallMeasMod( void )
            {

                measurementModel.CallMeasMod();

            }

    };



    int main( void )
    {

        KF kf([](int x, int y){ std::cout << (x+y) << std::endl; }, 3, 4 );         // Just a simple example function - in reality it could take any form and most likely wouldn't be a lambda function, but that's not particularly important at this stage.

        kf.CallMeasMod();


        //auto measurementModel = BindMeasMod([] (int a, int b) { std::cout << a + b << std::endl; }, 3, 4);        // <-- This would work because it by-passess the KF class - BUT it is not what I want

        //measurementModel.CallMeasMod();


        return 0;

    }

I'm sure the problem could probably be greatly simplified if the KF class was a template class, but I really don't want to have to do this. I don't know if Boost would provide some way of achieving what I want but I would prefer a STL based solution if possible. Many thanks in advance for anyone who can offer me any help on this.

I'm fairly new to variadic templates, and to be honest I still find them a bit confusing (e.g. I'm not 100% sure how the code in the Helper namespace works) so if anyone can also recommend a good book or website that explains them really well (for dummies) then that would also be appreciated.

P.S. I'm using g++ 4.8.4 on Ubuntu 14.04, if that matters.

Aucun commentaire:

Enregistrer un commentaire