持有成员函数指针和装饰成员函数指针的集合

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

作为一个更大项目的一部分,我的一个对象(MWE 中的 Thing)定义了一组过滤器(filterStrongfilterWeak)。 目标是使用complexFilteringProcedure中所有实现的过滤器,用户可以通过参数选择过滤规则,函数本身将取决于选择的过滤规则是否成功。 函数 complexFilteringProcedure 将作用于类型 Thing 的对象,并根据参数调用其私有方法之一(过滤规则)。

我通过在 filteringOptions 中持有所有可能的过滤器的 vector 并实现单个 public 过滤接口 filterUsingRule 来实现这一点。理想情况下,这将允许我稍后根据需要向项目添加新的过滤规则,并且只修改初始化过滤器列表的 setFilteringFunction

现在,我开始写一套新的过滤规则,发现所有的过滤规则都可以通过同样的方式修饰当前的过滤规则来获得(softenFilter;如果[=,请指正60=] 是这里的错误表达)。我记得最近读了 std::bind 并教过,太好了。 我还想在我的filteringOptions列表中添加所有装饰过滤规则,即每个原始过滤器装饰softenFilter

进一步阅读 std::bind,我认为我的问题可能有两个原因:

但是,我比这更困,不知道如何寻找解决我的特定问题的方法。我的主要问题是:可以实现这个功能吗?filterUsingRule的功能)而且,可以优雅地实现这个功能吗? (我知道我总是可以定义一组函数 bool softStrong(int param) { return softenFilter(filterStrong, param); } 手动将过滤器绑定到装饰器,但我希望 std::bind 或一些新的 C++ 魔法可以帮助实现这一点)。

重现我已经成功完成的和我想要实现的MWE如下:

#include <iostream>

#include <vector>
#include <functional>

class Thing{
    private:
        int basicFilter;

        typedef  bool (Thing::*filteringFunction)(int);

        static std::vector<filteringFunction> filteringOptions;

        bool filterStrong(int parameter) {return parameter > basicFilter*2;}
        bool filterWeak(int parameter) {return parameter > basicFilter;}

        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); // how? 
            filteringOptions.emplace_back(softWeak); // how?                                                               
        }

    public:
        Thing(int basicFilter) : basicFilter(basicFilter){
            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
    if (aThing.filterUsingRule(parameter, rule))
        std::cout << "Filtering with " << rule << "successful" << std::endl;
    else
        std::cout << "Filtering with " << rule << "failed" << std::endl;
    // and some more things
}


int main(void){
    Thing myThing(5), otherThing(10);

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

    complexFilteringProcedure(myThing, 7, 2); // how to do this correctly?
    complexFilteringProcedure(otherThing, 7, 3); // or this?
}

您必须使用 std::function as your vector element type. The key issue is that the object returned by std::bind() is not a bare function pointer. It is rather a Callable -- a function object -- it is some type (exactly what type is unimportant ) 的特化,它具有 operator() 和采用适当参数的适当 return 类型。这正是 std::function 的作用——一种可以包装任何具有正确签名的 Callable 的类型,无论 Callable 的实际类型如何,都可以使用已知的具体类型来处理它。

typedef std::function<bool(int)> filteringFunction;
static std::vector<filteringFunction> filteringOptions;

// now can you store your member function pointers in
// filteringOptions after bind()ing the first parameter
// as you've already done

为了打消怀疑者的疑虑,这里修改了 OP 的代码以使用此技术。

#include <iostream>

#include <vector>
#include <functional>

class Thing{
    private:
        int basicFilter;

        typedef std::function<bool(int)> filteringFunction;

        static std::vector<filteringFunction> filteringOptions;

        bool filterStrong(int parameter) {return parameter > basicFilter*2;}
        bool filterWeak(int parameter) {return parameter > basicFilter;}

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

        void setFilteringFunctions(void){
            filteringFunction strong = std::bind(&Thing::filterStrong,
                this, std::placeholders::_1);
            filteringFunction weak = std::bind(&Thing::filterWeak,
                this, std::placeholders::_1);

            filteringFunction softStrong = std::bind(&Thing::softenFilter,
                this, strong, std::placeholders::_1);
            filteringFunction softWeak = std::bind(&Thing::softenFilter,
                this, weak, std::placeholders::_1);

            filteringOptions.emplace_back(softStrong);
            filteringOptions.emplace_back(softWeak);
        }

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

        bool filterUsingRule(int parameter, int rule = 0){
            return ((int)Thing::filteringOptions.size() > rule) &&
                   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::endl;
    // and some more things
}


int main(void){
    Thing myThing(5), otherThing(10);

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

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

您可能会使用 std::function

using filteringFunction = std::function<bool (Thing&, int)>;

然后

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

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

    Thing::filteringOptions.emplace_back(&softStrong);
    Thing::filteringOptions.emplace_back(&softWeak);
    // or
    Thing::filteringOptions.emplace_back([](Thing& instance, int param){ 
        return instance.filterStrong(param + 2) });
}
typedef std::function<bool(Thing*, int)> filteringFuction;

现在您可以使用静态函数以及 std::bind 和 lambda 或任何接受 int 和 returns bool.

的可调用函数
    static bool test(Thing*, int);
    static bool decoratee(Thing*, bool , int);
    this->filteringOptions.emplace_back([](Thing* sth, int x){return false;});
    this->filteringOptions.emplace_back(&Thing::weakFilter);
    this->filteringOptions.emplace_back(std::bind(decoratee, _1, false, _2));
    this->filteringOptions.emplace_back(&test);

    int param;
    for(auto& callee:this->filteringOptions)
        callee(this,param);