C++ C++;绑定重载成员函数并作为参数传递

C++ C++;绑定重载成员函数并作为参数传递,c++,std-function,stdbind,C++,Std Function,Stdbind,我有一个类,它有两个函数,可以启动和停止一组东西。由于这两个函数是相同的,除了它们最终分别对每件事情调用start或stop函数外,我想重构代码,以便将代码主体移动到通用函数,我的start和stop集合调用这个传递一个额外的参数,这是它们必须调用以启动或停止的函数 当然,在线上有很多std::bind()教程和示例,但我没有发现任何文章或问题/答案涵盖我面临的以下所有具体约束: 被约束的函数是使事情复杂化的成员;它也是非常量的 被绑定的函数也被重载,因此必须正确区分 大多数std::bind

我有一个类,它有两个函数,可以启动和停止一组东西。由于这两个函数是相同的,除了它们最终分别对每件事情调用start或stop函数外,我想重构代码,以便将代码主体移动到通用函数,我的start和stop集合调用这个传递一个额外的参数,这是它们必须调用以启动或停止的函数

当然,在线上有很多
std::bind()
教程和示例,但我没有发现任何文章或问题/答案涵盖我面临的以下所有具体约束:

  • 被约束的函数是使事情复杂化的成员;它也是非常量的
  • 被绑定的函数也被重载,因此必须正确区分

  • 大多数
    std::bind()
    示例都使用
    auto
    ,但在这种情况下,我需要知道
    std::bind()
    返回的类型,以便将其作为参数传递给
    action\u widgets()
  • 有两个布尔值,
    a
    &
    b
    ,它们实际上是常量,可以绑定到函数中,尽管我在这里还没有这样做。一次只做一件事
下面是我试图实现的一个例子:

#include <string>
#include <vector>
#include <functional>

struct Processor {

    using WidgetActionFunction = bool(Processor::*)(const std::string&,
                                                    bool, bool);

    // Function wrapper 
    using WidgetActionWrapper = std::function<bool(Processor&,
                                                   const std::string&, bool, bool)>;

    // These functions in reality are tied heavily to the class and are quite
    // large. They cannot easily be made static or free.
    bool stop_widget(const std::string& key, bool a, bool b) { return true; }
    bool start_widget(const std::string& key, bool a, bool b) { return true; }

    // Just to make life difficult, there are some overloads, which we're not
    // interested in.
    bool stop_widget(int event, bool a, bool b) { return true; }
    bool start_widget(int event, bool a, bool b) { return true; }

    // I created this function because start_widgets() and stop_widgets() were
    // identical except that internally they call start_widget() and stop_widget()
    // respectively. I want the main body of the code to be here and for the
    // appropriate function to be passed in.
    void action_widgets(std::vector<std::string>& widgets,
            bool a, bool b, WidgetActionWrapper& func) {
        std::vector<std::string> valid_widgets;
        valid_widgets.reserve(widgets.size());
        for (const auto& widget : widgets) {
            if (func(*this, widget, a, b)) {  // This is where func() gets invoked.
                valid_widgets.push_back(widget);
            }
        }
        std::swap(widgets, valid_widgets);
    }

    void start_widgets(std::vector<std::string>& widgets, bool a, bool b) {
        WidgetActionWrapper func =
            std::bind(static_cast<WidgetActionFunction>(&Processor::start_widget),
                      this, std::placeholders::_1, a, b); // compilation fails here.
        action_widgets(widgets, a, b, func);
    }

    void stop_widgets(std::vector<std::string>& widgets, bool a, bool b) {
        // Very similar to start_widgets() but calls with bound stop_widget()
        // instead.
    }
};

int main()
{
    return 0;
}
#包括
#包括
#包括
结构处理器{
使用WidgetActionFunction=bool(处理器::*)(常量std::string&,
bool,bool);
//函数包装器
使用WidgetActionWrapper=std::函数;
//实际上,这些函数与类紧密相关,并且非常复杂
//大的。它们不容易固定或自由。
bool stop_小部件(const std::string&key,bool a,bool b){return true;}
bool start_小部件(const std::string&key,bool a,bool b){return true;}
//只是为了让生活变得困难,有一些超载,而我们不是
//对……感兴趣。
bool stop_小部件(int事件,bool a,bool b){return true;}
bool start_小部件(int事件,bool a,bool b){return true;}
//我创建这个函数是因为start\u widgets()和stop\u widgets()是
//除了在内部调用start_widget()和stop_widget()之外,其他都是相同的
//分别。我希望代码的主体在这里和
//要传入的适当函数。
void action_小部件(标准::向量和小部件,
布尔a、布尔b、WidgetActionWrapper和func){
std::vector-valid\u小部件;
有效的_widgets.reserve(widgets.size());
用于(常量自动和小部件:小部件){
如果(func(*this,widget,a,b)){//这是调用func()的地方。
有效的小部件。推回(小部件);
}
}
std::swap(小部件、有效的_小部件);
}
void start_小部件(std::vector&widgets、bool a、bool b){
WidgetActionWrapper函数=
std::bind(静态\u转换(&处理器::启动\u小部件),
这个,std::占位符::_1,a,b);//这里编译失败。
action_小部件(小部件、a、b、func);
}
void stop_小部件(std::vector&widgets、bool a、bool b){
//非常类似于start_widgets(),但使用绑定的stop_widget()调用
//相反。
}
};
int main()
{
返回0;
}
编译时,我得到以下错误:

error: conversion from ‘std::_Bind_helper<false, bool (Processor::*)(const std::basic_string<char>&, bool, bool), Processor* const, const std::_Placeholder<1>&, bool&, bool&>::type {aka std::_Bind<std::_Mem_fn<bool (Processor::*)(const std::basic_string<char>&, bool, bool)>(Processor*, std::_Placeholder<1>, bool, bool)>}’ to non-scalar type ‘Processor::WidgetActionFunctor {aka std::function<bool(Processor&, const std::basic_string<char>&, bool, bool)>}’ requested
错误:请求从'std::_Bind_helper::type{aka std::_Bind}'转换为非标量类型'Processor::WidgetActionFunctor{aka std::function}'
显然,我的函数包装器别名与
std::bind()
返回的内容不匹配,但我哪里出错了


最后一点警告:因为这是针对公司客户的,所以我只能使用C++11解决方案(尽管为其他人的利益提供的解决方案受到赞赏),而且,尽管我热衷于使用lambdas的更简单的解决方案,但我的同事认为,从技术角度来看,这可能同样棘手,我很想知道我错了什么。

您可以将
std::bind
看作是在分配给
std::函数时去掉了前几个参数

例如,这:

bool(Processor::*)(const std::string&, bool, bool);

// Which is this:
class Processor { bool f(const std::string&, bool, bool); }
decltype(&Processor::f)
分配给
std::函数

当您将它绑定到一个
处理器&
(在您的例子中,
*this
,就像
std::bind(&Processor::f,*this)
),它现在应该被分配到
std::函数
(因为
bind
摆脱了
处理器&
参数)

这里有两个修正。不要绑定:

WidgetActionWrapper func =
    std::bind(static_cast<WidgetActionFunction>(&Processor::start_widget),
              *this, std::placeholders::_1, a, b); // compilation fails here.
// becomes
WidgetActionWrapper func = &Processor::start_widget;

我认为这里不需要lambda或
std::bind
,尤其不需要
std::function
,以及它将引入的所有开销。您可以简单地使用一个成员函数模板,该模板被赋予一个指向实际成员函数的指针,以调用每个小部件作为模板参数,例如:

struct Processor
{
    bool stop_widget(const std::string& key, bool a, bool b) { return true; }
    bool start_widget(const std::string& key, bool a, bool b) { return true; }

    bool stop_widget(int event, bool a, bool b) { return true; }
    bool start_widget(int event, bool a, bool b) { return true; }

    template <bool (Processor::* func)(const std::string&, bool, bool)>
    void action_widgets(std::vector<std::string>& widgets, bool a, bool b)
    {
        std::vector<std::string> valid_widgets;
        valid_widgets.reserve(widgets.size());
        for (const auto& widget : widgets)
        {
            if ((this->*func)(widget, a, b))
            {
                valid_widgets.push_back(widget);
            }
        }
        std::swap(widgets, valid_widgets);
    }
};
struct处理器
{
bool stop_小部件(const std::string&key,bool a,bool b){return true;}
bool start_小部件(const std::string&key,bool a,bool b){return true;}
bool stop_小部件(int事件,bool a,bool b){return true;}
bool start_小部件(int事件,bool a,bool b){return true;}
模板
void action_小部件(std::vector&widgets、bool a、bool b)
{
std::vector-valid\u小部件;
有效的_widgets.reserve(widgets.size());
用于(常量自动和小部件:小部件)
{
如果((此->*func)(小部件,a,b))
{
有效的小部件。推回(小部件);
}
}
std::swap(小部件、有效的_小部件);
}
};
然后

processor.action_widgets<&Processor::start_widget>(widgets, true, false);
processor.action_widgets<&Processor::stop_widget>(widgets, true, false);
processor.action\u小部件(小部件,真、假);
processor.action_小部件(小部件,true、false);

这基本上只会导致编译器为您生成原始的
start\u小部件
stop\u小部件
函数,就像您
processor.action_widgets<&Processor::start_widget>(widgets, true, false);
processor.action_widgets<&Processor::stop_widget>(widgets, true, false);