保存成员函数指针和装饰成员函数指针

时间:2018-04-05 16:25:57

标签: c++ c++11 member-function-pointers

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

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

现在,我开始编写一组新的过滤规则,并且通过以相同的方式(softenFilter完成当前过滤规则的设计来实现所有过滤规则:如果“装饰”是这里的错误表达)。我记得最近读到std::bind并且教了很多。 我还想在filteringOptions 列表中添加所有已修饰的过滤规则,即每个使用softenFilter修饰的原始过滤器。

std::bind上阅读更多内容,我认为我遇到问题的可能原因有两个:

  • std::bind的返回类型是模糊的混乱,绝对不是Thing::filteringFunction
  • 在定义thissoftStrong
  • 时,我可能会绑定引用调用对象的softWeak

但是,我更进一步,不知道如何寻找我的具体问题的解决方案。我的主要问题是:是否可以实现此功能?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?
}

3 个答案:

答案 0 :(得分:3)

您可以使用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) });
}

答案 1 :(得分:0)

您必须使用std::function的特化作为向量元素类型。关键问题是std::bind() 返回的对象不是裸函数指针。它是一个Callable - 一个函数对象 - 它是一些类型(确切地说是什么类型是不重要的and in fact unspecified),它具有operator()和适当的std::function返回类型,它采用适当的参数。这正是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 的作用 - 一种类型,它可以以一种允许您使用已知具体类型处理它的方式包装正确签名的任何Callable,而不管Callable的实际类型。

#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?
}

为了满足怀疑者的需要,这里修改了OP代码以使用这种技术。

<% if v >= 1 %>

答案 2 :(得分:0)

typedef std::function<bool(Thing*, int)> filteringFuction;

现在您可以使用静态函数以及std::bind和lambda或任何接受int并返回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);