【发布时间】:2019-05-01 09:48:25
【问题描述】:
我有一个具有两个函数的类,它们启动和停止事物的集合。由于这两个函数是相同的,除了它们最终分别在每个事物上调用启动或停止函数,我想重构代码,以便将代码主体移动到通用函数,并且我的启动和停止集合调用这个传入一个额外的参数,这是他们必须调用才能启动或停止的函数。
当然,网上有很多 std::bind() 教程和示例,但我在这里没有找到任何文章或问题/答案涵盖所有我面临的以下具体限制:
- 被绑定的函数是一个使事情复杂化的成员;它也是非常量的
- 被绑定的函数也是重载的,所以必须正确区分
- 大多数
std::bind()示例使用auto,但在这种情况下,我需要知道std::bind()的返回类型,以便作为参数传递给action_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;
}
编译时出现以下错误:
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() 返回的内容不匹配,但我哪里出错了?
最后一两个警告:因为这是针对企业客户的,所以我仅限于 C++11 解决方案(尽管赞赏为他人利益的解决方案),而且,虽然我热衷于使用更简单的解决方案lambdas,同事让我相信这可能同样棘手,无论如何,从技术角度来看,我很想知道我做错了什么。
【问题讨论】:
-
“我需要知道来自
std::bind()的返回类型,以便作为参数传递给action_widgets()”,但您没有将任何类型信息传递给action_widgets。请创建一个minimal reproducible example。 -
对不起,我不明白你的意思。这是一个 MCVE,但如果有帮助,我会添加
main()。action_widgets()的第四个参数是绑定函数。这不会编译,因为我当前使用的类型WidgetActionWrapper与std::bind()返回的不匹配。我需要了解它返回的内容,以便相应地更改第四个参数的类型。 -
使用 lambdas 代替
std::bind。话虽如此,您只传递一个占位符进行绑定,因此您得到的函数对象将具有签名bool(int),然后您尝试使用所有四个参数调用(并传递)它。
标签: c++ std-function stdbind