jeudi 5 avril 2018

Hold a collection of member function pointers and decorated member function pointers

As a part of a much larger project, one of my objects (Thing in MWE) has a set of filters (filterStrong, filterWeak) defined on it. These filters are used in a complexFilteringProcedure, allowing for choice of filtering rule, where decisions depend on the success of the chosen filtering operation.

I implemented this by holding a vector of all possible filters in filteringOptions and implementing a single public filtering interface, filterUsingRule. Ideally, this would allow me to later on add new filtering rules to the project as I need them, and only modify the setFilteringFunction where the filter list is initialized.

Now, I started writing a new set of filtering rules, and realized all of them could be obtained by decorating the current filtering rules all in the same manner (softenFilter; please do correct me if "decorating" is the wrong expression here). In the actual implementations, all of these methods require access to private members of the Thing. I remembered reading into std::bind recently and taught, great.

Reading up a little bit more on std::bind, I think the possible reasons for my problems are twofold:

  • the return type of std::bind is a templated mess, and definitely not Thing::filteringFunction
  • I might be binding the this referring to the calling object when defining softStrong and softWeak

But, I am stuck further than that, not sure how to look for a solution to my specific problem. My main question are: Can this functionality be achieved? (functionality of filterUsingRule) and further, Can this functionality be achieved elegantly? (I know I could always define a set of functions bool softStrong(int param) { return softenFilter(filterStrong, param); } that manually bind the filters to the decorator, but I was hoping that std::bind or some new C++ magic would help with that).

The MWE recreating what I have successfully done and what I would like to achieve is as follows:

#include <iostream>
#include <vector>
#include <functional>

class Thing{
    private:
        typedef  bool (Thing::*filteringFunction)(int);

        static std::vector<filteringFunction> filteringOptions;

        bool filterStrong(int parameter) {return parameter > 10;}
        bool filterWeak(int parameter) {return parameter > 5;}

        bool softenFilter(filteringFunction f, int parameter){
            if (!((this->*(f))(parameter)))
                return (this->*(f))(parameter+2);
            return true;
        }

        void setFilteringFunctions(void){
            Thing::filteringOptions.emplace_back(&Thing::filterStrong);
            Thing::filteringOptions.emplace_back(&Thing::filterWeak);

            auto softStrong = std::bind(&Thing::softenFilter,
                                        &Thing::filterStrong,
                                        std::placeholders::_1); // ok
            auto softWeak = std::bind(&Thing::softenFilter,
                                      &Thing::filterWeak,
                                      std::placeholders::_1); // ok

            //filteringOptions.emplace_back(&softStrong); // not ok
            //filteringOptions.emplace_back(softWeak); // not ok
        }

    public:
        Thing(){
            if (Thing::filteringOptions.empty())
                setFilteringFunctions();
        }

        bool filterUsingRule(int parameter, int rule = 0){
            return ((int)Thing::filteringOptions.size() > rule) &&
                   (this->*(Thing::filteringOptions[rule]))(parameter);
        }

};

std::vector <Thing::filteringFunction> Thing::filteringOptions(0);

void complexFilteringProcedure(Thing &aThing, int parameter, int rule){
    // do a lot of things
    std::cout << "Filtering: " << aThing.filterUsingRule(parameter, rule);
    std::cout << std::endl;
    // and some more things
}


int main(void){
    Thing myThing;

    complexFilteringProcedure(myThing, 7, 0); // uses strong rule
    complexFilteringProcedure(myThing, 7, 1); // uses weak rule

    //complexFilteringProcedure(myThing, 7, 2); // how to use soft strong rule?
    //complexFilteringProcedure(myThing, 7, 3); // how to use soft weak rule?
}

Aucun commentaire:

Enregistrer un commentaire