std::bind, mem_fn,for_each
1、常函数中 mutable 的作用?
函数被声明为常函数意味着告诉使用者不会修改任何非静态数据成员,使用 mutable 表明在常成员函数中可以灵活地修改特定的成员变量。
2、boost::bind 怎么可以用仿函数代替
std::bind 是 C++11 引入的一个工具,用于创建函数对象或可调用对象,它可以将函数的某些参数绑定到特定值上,从而生成一个新的可调用对象。
std::bind的使用
template< class F, class... Args >
auto bind(F&& f, Args&&... args) -> decltype(...);
Parameters
f - 函数对象、指向函数的指针、对函数的引用、指向成员函数的指针 或 指向数据成员的指针
args: 要绑定的参数列表,其中未绑定的参数由占位符替换
1、绑定普通函数
#include <functional>
#include <iostream>
#include <memory>
#include <random>
void f(int n1, int n2, int n3, const int& n4, int n5)
{
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
int g(int n1)
{
return n1;
}
struct Foo
{
void print_sum(int n1, int n2)
{
std::cout << n1 + n2 << '\n';
}
int data = 10;
};
int main()
{
using namespace std::placeholders; // for _1, _2, _3...
std::cout << "1) argument reordering and pass-by-reference: ";
int n = 7;
// 1、绑定普通函数
// (_1 and _2 are from std::placeholders, and represent future
// arguments that will be passed to f1)
auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
n = 10;
f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
// makes a call to f(2, 42, 1, n, 7)
std::cout << "2) achieving the same effect using a lambda: ";
n = 7;
auto lambda = [&ncref = n, n](auto a, auto b, auto /*unused*/)
{
f(b, 42, a, ncref, n);
};
n = 10;
lambda(1, 2, 1001); // same as a call to f1(1, 2, 1001)
// 2、绑定成员函数方式一
std::cout << "5) bind to a pointer to member function: ";
Foo foo;
auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
f3(5);
// 2、绑定成员函数方式二 使用 std::mem_fn
std::cout << "6) bind to a mem_fn that is a pointer to member function: ";
auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1);
f4(5);
// 3、绑定成员变量方式一
std::cout << "7) bind to a pointer to data member: ";
auto f5 = std::bind(&Foo::data, _1);
std::cout << f5(foo) << '\n';
// 3、绑定成员变量方式二,使用 std::mem_fn
std::cout << "8) bind to a mem_fn that is a pointer to data member: ";
auto ptr_to_data = std::mem_fn(&Foo::data);
ptr_to_data(foo);
// 不一定需要再次 bind了,bind 不 bind 无所谓。
// auto f6 = std::bind(ptr_to_data, _1);
// std::cout << f6(foo) << '\n';
}
特殊使用场景:
这种场景下可以使用 std::bind 当我们有时候可能并不一定能够一次
性获得调用某个函数的全部参数,通过这个函数,我们可以将部分调用参数提前绑定到函数身上成为一
个新的对象,然后在参数齐全后,完成调用。
int foo(int a, int b, int c)
{
......
}
int main () {
// 将 参 数1 ,2 绑 定 到 函 数 foo 上 , 但 是 使 用 std :: placeholders :: _1 来 对 第 一 个 参数 进 行 占 位
auto bindFoo = std :: bind (foo , std :: placeholders ::_1 , 1 ,2);
// 这 时 调 用 bindFoo 时 , 只 需 要 提 供 第 一 个 参 数 即 可
bindFoo(1);
}
3、for_each的用法 https://en.cppreference.com/w/cpp/algorithm/for_each的用法
std::for_each 提供了一种简洁且高效的方式来遍历容器中的元素,可以指定一个一元函数对每个元素执行指定的操作。
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{3, -4, 2, -8, 15, 267};
auto print = [](const int& n) { std::cout << n << ' '; };
std::cout << "before:\t";
std::for_each(v.cbegin(), v.cend(), print);
std::cout << '\n';
// increment elements in-place
std::for_each(v.begin(), v.end(), [](int &n) { n++; });
std::cout << "after:\t";
std::for_each(v.cbegin(), v.cend(), print);
std::cout << '\n';
struct Sum
{
void operator()(int n) { sum += n; }
int sum {0};
};
// invoke Sum::operator() for each element
Sum s = std::for_each(v.cbegin(), v.cend(), Sum());
std::cout << "sum:\t" << s.sum << '\n';
}
wrapper(适配器)
std::mem_fn 是一个适用于成员函数的适配器,它用于创建一个可调用对象,以便调用类的成员函数。它简化了成员函数的调用,使得其可以像普通函数一样使用。
template< class M, class T >
/* unspecified */ mem_fn( M T::* pm ) noexcept;
参数:pm 成员函数指针 (这里又可以详细讲解下函数指针和成员函数指针。)
使用示例:
https://en.cppreference.com/w/cpp/utility/functional/mem_fn
template<typename... Args> int add_many(Args... args)
{
return data + (args + ...);
}
#include <iostream>
#include <functional>
class Foo {
public:
void print_sum(int n1, int n2) {
std::cout << "Sum: " << n1 + n2 << '\n';
}
};
int main() {
Foo foo;
// 使用 std::mem_fn 创建可调用对象
auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
// 直接调用,传递所有参数
ptr_to_print_sum(foo, 95, 5); // 输出: Sum: 100
// 如果需要使用占位符,则需要借助 std::bind
// 使用 std::bind 和占位符
// auto f4 = std::bind(ptr_to_print_sum, &foo, 95, std::placeholders::_1);
// 调用 f4,传入第二个参数
// f4(5); // 输出: Sum: 100
return 0;
}
函数被声明为常函数意味着告诉使用者不会修改任何非静态数据成员,使用 mutable 表明在常成员函数中可以灵活地修改特定的成员变量。
2、boost::bind 怎么可以用仿函数代替
std::bind 是 C++11 引入的一个工具,用于创建函数对象或可调用对象,它可以将函数的某些参数绑定到特定值上,从而生成一个新的可调用对象。
std::bind的使用
template< class F, class... Args >
auto bind(F&& f, Args&&... args) -> decltype(...);
Parameters
f - 函数对象、指向函数的指针、对函数的引用、指向成员函数的指针 或 指向数据成员的指针
args: 要绑定的参数列表,其中未绑定的参数由占位符替换
1、绑定普通函数
#include <functional>
#include <iostream>
#include <memory>
#include <random>
void f(int n1, int n2, int n3, const int& n4, int n5)
{
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
int g(int n1)
{
return n1;
}
struct Foo
{
void print_sum(int n1, int n2)
{
std::cout << n1 + n2 << '\n';
}
int data = 10;
};
int main()
{
using namespace std::placeholders; // for _1, _2, _3...
std::cout << "1) argument reordering and pass-by-reference: ";
int n = 7;
// 1、绑定普通函数
// (_1 and _2 are from std::placeholders, and represent future
// arguments that will be passed to f1)
auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
n = 10;
f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
// makes a call to f(2, 42, 1, n, 7)
std::cout << "2) achieving the same effect using a lambda: ";
n = 7;
auto lambda = [&ncref = n, n](auto a, auto b, auto /*unused*/)
{
f(b, 42, a, ncref, n);
};
n = 10;
lambda(1, 2, 1001); // same as a call to f1(1, 2, 1001)
// 2、绑定成员函数方式一
std::cout << "5) bind to a pointer to member function: ";
Foo foo;
auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
f3(5);
// 2、绑定成员函数方式二 使用 std::mem_fn
std::cout << "6) bind to a mem_fn that is a pointer to member function: ";
auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1);
f4(5);
// 3、绑定成员变量方式一
std::cout << "7) bind to a pointer to data member: ";
auto f5 = std::bind(&Foo::data, _1);
std::cout << f5(foo) << '\n';
// 3、绑定成员变量方式二,使用 std::mem_fn
std::cout << "8) bind to a mem_fn that is a pointer to data member: ";
auto ptr_to_data = std::mem_fn(&Foo::data);
ptr_to_data(foo);
// 不一定需要再次 bind了,bind 不 bind 无所谓。
// auto f6 = std::bind(ptr_to_data, _1);
// std::cout << f6(foo) << '\n';
}
特殊使用场景:
这种场景下可以使用 std::bind 当我们有时候可能并不一定能够一次
性获得调用某个函数的全部参数,通过这个函数,我们可以将部分调用参数提前绑定到函数身上成为一
个新的对象,然后在参数齐全后,完成调用。
int foo(int a, int b, int c)
{
......
}
int main () {
// 将 参 数1 ,2 绑 定 到 函 数 foo 上 , 但 是 使 用 std :: placeholders :: _1 来 对 第 一 个 参数 进 行 占 位
auto bindFoo = std :: bind (foo , std :: placeholders ::_1 , 1 ,2);
// 这 时 调 用 bindFoo 时 , 只 需 要 提 供 第 一 个 参 数 即 可
bindFoo(1);
}
3、for_each的用法 https://en.cppreference.com/w/cpp/algorithm/for_each的用法
std::for_each 提供了一种简洁且高效的方式来遍历容器中的元素,可以指定一个一元函数对每个元素执行指定的操作。
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{3, -4, 2, -8, 15, 267};
auto print = [](const int& n) { std::cout << n << ' '; };
std::cout << "before:\t";
std::for_each(v.cbegin(), v.cend(), print);
std::cout << '\n';
// increment elements in-place
std::for_each(v.begin(), v.end(), [](int &n) { n++; });
std::cout << "after:\t";
std::for_each(v.cbegin(), v.cend(), print);
std::cout << '\n';
struct Sum
{
void operator()(int n) { sum += n; }
int sum {0};
};
// invoke Sum::operator() for each element
Sum s = std::for_each(v.cbegin(), v.cend(), Sum());
std::cout << "sum:\t" << s.sum << '\n';
}
wrapper(适配器)
std::mem_fn 是一个适用于成员函数的适配器,它用于创建一个可调用对象,以便调用类的成员函数。它简化了成员函数的调用,使得其可以像普通函数一样使用。
template< class M, class T >
/* unspecified */ mem_fn( M T::* pm ) noexcept;
参数:pm 成员函数指针 (这里又可以详细讲解下函数指针和成员函数指针。)
使用示例:
https://en.cppreference.com/w/cpp/utility/functional/mem_fn
template<typename... Args> int add_many(Args... args)
{
return data + (args + ...);
}
#include <iostream>
#include <functional>
class Foo {
public:
void print_sum(int n1, int n2) {
std::cout << "Sum: " << n1 + n2 << '\n';
}
};
int main() {
Foo foo;
// 使用 std::mem_fn 创建可调用对象
auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);
// 直接调用,传递所有参数
ptr_to_print_sum(foo, 95, 5); // 输出: Sum: 100
// 如果需要使用占位符,则需要借助 std::bind
// 使用 std::bind 和占位符
// auto f4 = std::bind(ptr_to_print_sum, &foo, 95, std::placeholders::_1);
// 调用 f4,传入第二个参数
// f4(5); // 输出: Sum: 100
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了