我知道什么是仿函数以及何时将它们与stl algos一起使用.但不明白他在这个主题中的意思:
任何人都可以解释什么是什么std
,什么std::bind
时候应该使用,新手的一些例子?
这两者有什么区别吗?还是我的安全,以取代所有出现boost::bind
的std::bind
在我的代码,从而消除对加速的依赖?
正如在一个类似措辞的问题中提到的(为什么在 c++14 中使用 bind over lambdas?)答案是 - 没有理由(并且还提到为什么使用 lambdas 会更好)。
我的问题是 - 如果在 C++14 中不再有理由使用绑定,为什么标准委员会认为有必要std::bind_front
在 C++20 中添加?
它现在比 lambda 有什么新优势吗?
我有以下代码:
#include <stdio.h>
#include <functional>
template <typename T>
auto callback(T&& func) ->decltype(func())
{
return func();
}
double test(double& value)
{
value=value+1.0;
return value;
}
int main(void)
{
double t=1.0;
printf("%f\n",t);
test(t);
printf("%f\n",t);
callback(std::bind(test,t));
printf("%f\n",t);
}
Run Code Online (Sandbox Code Playgroud)
它输出
1.000000
2.000000
2.000000
Run Code Online (Sandbox Code Playgroud)
这意味着该callback
函数获得了副本t
而不是引用t
.我想知道发生了什么,因为std::bind
它应该是完美的转发.
我正在使用std::bind
但是当我们将它与成员类函数一起使用时,我仍然不知道它是如何工作的.
如果我们有以下功能:
double my_divide (double x, double y) {return x/y;}
Run Code Online (Sandbox Code Playgroud)
我完全理解下一行代码:
auto fn_half = std::bind (my_divide,_1,2); // returns x/2
std::cout << fn_half(10) << '\n'; // 5
Run Code Online (Sandbox Code Playgroud)
但是现在,通过以下代码我们有一个绑定到成员函数我有一些问题.
struct Foo {
void print_sum(int n1, int n2)
{
std::cout << n1+n2 << '\n';
}
int data = 10;
};
Foo foo;
auto f = std::bind(&Foo::print_sum, &foo, 95, _1);
f(5);
Run Code Online (Sandbox Code Playgroud)
为什么第一个参数是参考?我想得到一个理论上的解释.
第二个参数是对象的引用,对我来说是最复杂的部分需要理解.我认为这是因为std::bind
需要一个背景,我是对的吗?总是这样吗?std::bind
当第一个参数是成员函数时,是否有某种实现要求引用?
假设我有一个带两个参数的函数,
void f(int x, int y);
Run Code Online (Sandbox Code Playgroud)
我想绑定其中一个.我可以使用std::bind
如下:
auto partiallyBoundF = std::bind(f, 10, _1);
Run Code Online (Sandbox Code Playgroud)
partiallyBoundF
只需要一个参数,但我可以用多个参数调用它.超越第一个的论点甚至不必是一个有意义的类型:
partiallyBoundF(20, 0);
partiallyBoundF(0, 44, -99, "Hello", 4.5, true, []{});
Run Code Online (Sandbox Code Playgroud)
允许返回的对象bind
传递额外参数的目的是什么?它允许编译调用错误,否则将被拒绝.
例如,这是我的成员函数(do_it
):
class oops
{
public:
void do_it(GtkWidget *widget, GdkEvent *event, gpointer data)
{
g_print ("Hi there :)\n");
}
};
Run Code Online (Sandbox Code Playgroud)
...我用std::bind
它来使它看起来像一个非成员函数:
oops o;
std::function<void(GtkWidget*, GdkEvent*, gpointer)> f = std::bind(&oops::do_it, o);
Run Code Online (Sandbox Code Playgroud)
但它不起作用,以下是编译器错误消息:
program.cc: In function ‘int main(int, char**)’:
program.cc:69:85: error: conversion from ‘std::_Bind_helper<false, void (oops::*)(_GtkWidget*, _GdkEvent*, void*), oops&>::type {aka std::_Bind<std::_Mem_fn<void (oops::*)(_GtkWidget*, _GdkEvent*, void*)>(oops)>}’ to non-scalar type ‘std::function<void(_GtkWidget*, _GdkEvent*, void*)>’ requested
std::function<void(GtkWidget*, GdkEvent*, gpointer)> f = std::bind(&oops::do_it, o);
^
Run Code Online (Sandbox Code Playgroud)
我必须使用std::placeholders
以下方法修复它:
oops o;
std::function<void(GtkWidget*, GdkEvent*, gpointer)> f = …
Run Code Online (Sandbox Code Playgroud) 我有以下代码将成员函数绑定到类的实例:
class Foo {
public:
int i;
void test() {
std::cout << i << std::endl;
}
};
int main() {
Foo f;
f.i = 100;
auto func = std::bind(&Foo::test, std::forward<Foo>(f));
f.i = 1000;
func();
}
Run Code Online (Sandbox Code Playgroud)
但该std::bind
声明并未f
通过引用绑定.调用func
打印"100"而不是"1000"这是我想要的.
但是,如果我更改语句以获取指针它是否有效.
auto func = std::bind(&Foo::test, &f);
Run Code Online (Sandbox Code Playgroud)
但是,这是通过f
由指针我的理解,因为我认为std::bind
需要一个R值的参考Arg&&
(如图所示这里)如何工作的呢?
有人可以解释一下吗?
我std::bind
在第32小节中读到了N3225中的描述20.8.10.1
.它说下面应该打印1
,但我认为bind
应该复制它的参数,因此它应该打印0
.如果想要引用传递的参数,则需要使用std::ref
,对吧?
void f(int &a) { a = 1; }
int main() {
int a = 0;
std::bind(f, a)();
std::cout << a << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
海湾合作委员会的产出0
,同意我认为的工作.但是N3225说std::bind(f, a1)
应该返回一个调用包装器,当调用时wrapper()
将调用INVOKE(f, v1)
,其中v1
应该是a
(我传入的参数,换句话说,使用binds
传入的参数,这是一个完美的转发参数std::forward<A1>(a1)
).
INVOKE(f, a)
由20.8.2定义为f(a)
.因此,这定义了对返回的调用包装器的调用传递原始参数.我错过了什么?
我想知道如何做到以下几点
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, s)(); // Error.
bind(f, move(s))(); // Error.
bind(f, ref(s))(); // Error.
}
Run Code Online (Sandbox Code Playgroud)
如何传递rvalue引用并将其作为rvalue引用(可能包装)存储在调用包装器中?我知道我可以手动编写一个类似于std::reference_wrapper<>
具有转换功能的类T&&
,但我宁愿避免这种情况并使用标准技术.
我像AProgrammer推荐的那样实现了它:
template<typename T> struct adv {
T t;
explicit adv(T &&t):t(forward<T>(t)) {}
template<typename ...U> T &&operator()(U &&...) {
return forward<T>(t);
}
};
template<typename T> adv<T> make_adv(T &&t) {
return adv<T>{forward<T>(t)};
}
namespace std {
template<typename T>
struct is_bind_expression< adv<T> > : std::true_type {};
}
Run Code Online (Sandbox Code Playgroud)
现在我可以说 …
c++ ×10
stdbind ×10
c++11 ×7
bind-front ×1
boost ×1
boost-bind ×1
c++20 ×1
function ×1
lambda ×1
std ×1
std-function ×1