您的位置:首页 > 财经 > 金融 > 免费网站知乎_什么是o2o电商模式_新闻热点_厦门seo顾问

免费网站知乎_什么是o2o电商模式_新闻热点_厦门seo顾问

2025/3/13 19:14:53 来源:https://blog.csdn.net/haokan123456789/article/details/146025947  浏览:    关键词:免费网站知乎_什么是o2o电商模式_新闻热点_厦门seo顾问
免费网站知乎_什么是o2o电商模式_新闻热点_厦门seo顾问

目录

1.简介

2.使用

2.1.绑定普通函数

2.2.绑定成员函数

2.3.与STL算法搭配使用

3.实现原理

4.注意事项

5.总结


1.简介

C++中的std::bind深入剖析-CSDN博客

   std::bind_front是C++20 新引入的一个函数模板。它住在<functional>这个头文件里,和我们熟悉的std::bind有点像,但又有着自己独特的魅力和功能。std::bind_front的主要任务,就是把一个可调用对象(这个可调用对象可以是普通函数、函数对象,也可以是成员函数)和一系列参数绑在一起。这里有个小特点,这些绑上去的参数,是从左到右,依次填到原函数参数列表的前面部分。绑好之后,就会生成一个新的可调用对象。当我们调用这个新对象的时候,它会先用上之前绑好的前几个参数,再结合我们调用时传进去的参数,去调用原来的那个可调用对象。这就好比组装一台复杂的机器,我们提前把一部分固定的零件安装好,之后要用这台机器的时候,只需要再装上剩下的零件,它就能正常运转啦。

template< class F, class... Args >
constexpr /*unspecified*/ bind_front( F&& f, Args&&... args );
  • F:可调用对象的类型,如函数、函数指针、成员函数指针、函数对象等。
  • Args:要预先绑定到可调用对象 f 前面的参数类型。

   工作原理

   std::bind_front 返回一个新的可调用对象,该对象在调用时会将预先绑定的参数传递给原始的可调用对象,并且可以在调用时提供剩余的参数。

2.使用

2.1.绑定普通函数

#include <iostream>
#include <functional>// 普通函数
int add(int a, int b) {return a + b;
}int main() {// 使用 std::bind_front 绑定第一个参数为 3auto addThree = std::bind_front(add, 3);// 调用绑定后的函数对象,只需要提供剩余的参数int result = addThree(5);std::cout << "Result: " << result << std::endl;return 0;
}

在这个示例中,std::bind_front 绑定了 add 函数的第一个参数为 3,返回一个新的可调用对象 addThree。调用 addThree 时,只需要提供第二个参数,它会自动将预先绑定的 3 作为第一个参数传递给 add 函数。

2.2.绑定成员函数

#include <iostream>
#include <functional>class Calculator {
public:int multiply(int a, int b) {return a * b;}
};int main() {Calculator calc;// 使用 std::bind_front 绑定成员函数和对象实例auto multiplyByTwo = std::bind_front(&Calculator::multiply, &calc, 2);// 调用绑定后的函数对象,只需要提供剩余的参数int result = multiplyByTwo(4);std::cout << "Result: " << result << std::endl;return 0;
}

在这个示例中,std::bind_front 绑定了 Calculator 类的成员函数 multiply、对象实例 calc 以及第一个参数 2,返回一个新的可调用对象 multiplyByTwo。调用 multiplyByTwo 时,只需要提供第二个参数,它会自动调用 calc 对象的 multiply 成员函数,并将预先绑定的 2 作为第一个参数传递。

2.3.与STL算法搭配使用

   std::bind_front还有个超厉害的本事,就是能和标准模板库(STL)里的算法配合得默契十足,发挥出更大的威力。比如说,我们有一个整数向量vector<int>,现在想找出这个向量里所有大于某个固定值的元素个数。这时候,我们就可以借助std::count_if算法和std::bind_front来实现,看下面的代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>int main() {std::vector<int> numbers = {1, 5, 3, 7, 4, 9, 6};int fixedValue = 5;// 使用std::bind_front结合std::count_if算法auto count = std::count_if(numbers.begin(), numbers.end(), std::bind_front(std::greater<int>(), fixedValue));std::cout << "Number of elements greater than " << fixedValue << " is: " << count << std::endl;return 0;
}

在这个例子里,std::bind_front(std::greater<int>(), fixedValue)创建了一个新的可调用对象。这个新对象的作用就是判断一个数是不是大于fixedValue。然后std::count_if算法就利用这个新的可调用对象,去统计向量numbers里大于fixedValue的元素个数。这种搭配使用的方式,让代码既简洁又高效,充分展示了C++ 标准库的强大之处,是不是感觉像打开了新世界的大门。

3.实现原理

以vs2019的源码实现为例:

// FUNCTION TEMPLATE bind_front
template <class _Fx, class... _Types>
_NODISCARD constexpr auto bind_front(_Fx&& _Func, _Types&&... _Args) {static_assert(is_constructible_v<decay_t<_Fx>, _Fx>,"std::bind_front requires the decayed callable to be constructible from an undecayed callable");static_assert(is_move_constructible_v<decay_t<_Fx>>,"std::bind_front requires the decayed callable to be move constructible");static_assert(conjunction_v<is_constructible<decay_t<_Types>, _Types>...>,"std::bind_front requires the decayed bound arguments to be constructible from undecayed bound arguments");static_assert(conjunction_v<is_move_constructible<decay_t<_Types>>...>,"std::bind_front requires the decayed bound arguments to be move constructible");return _Front_binder<decay_t<_Fx>, decay_t<_Types>...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
}

首先用static_assert编译时检查传入参数的合法性,然后直接返回一个配接器_Front_binder:

// CLASS TEMPLATE _Front_binder
template <class _Fx, class... _Types>
class _Front_binder { // wrap bound callable object and arguments
private:using _Seq = index_sequence_for<_Types...>;_Compressed_pair<_Fx, tuple<_Types...>> _Mypair;_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Fx, decay_t<_Fx>>);_STL_INTERNAL_STATIC_ASSERT((is_same_v<_Types, decay_t<_Types>> && ...));public:template <class _FxInit, class... _TypesInit,enable_if_t<sizeof...(_TypesInit) != 0 || !is_same_v<remove_cvref_t<_FxInit>, _Front_binder>, int> = 0>constexpr explicit _Front_binder(_FxInit&& _Func, _TypesInit&&... _Args): _Mypair(_One_then_variadic_args_t{}, _STD forward<_FxInit>(_Func), _STD forward<_TypesInit>(_Args)...) {}template <class... _Unbound>constexpr auto operator()(_Unbound&&... _Unbargs) & noexcept(noexcept(_Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)))-> decltype(_Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)) {return _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...);}template <class... _Unbound>constexpr auto operator()(_Unbound&&... _Unbargs) const& noexcept(noexcept(_Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)))-> decltype(_Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...)) {return _Call_front_binder(_Seq{}, _Mypair._Get_first(), _Mypair._Myval2, _STD forward<_Unbound>(_Unbargs)...);}template <class... _Unbound>constexpr auto operator()(_Unbound&&... _Unbargs) && noexcept(noexcept(_Call_front_binder(_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)))-> decltype(_Call_front_binder(_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)) {return _Call_front_binder(_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...);}template <class... _Unbound>constexpr auto operator()(_Unbound&&... _Unbargs) const&& noexcept(noexcept(_Call_front_binder(_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)))-> decltype(_Call_front_binder(_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...)) {return _Call_front_binder(_Seq{}, _STD move(_Mypair._Get_first()), _STD move(_Mypair._Myval2), _STD forward<_Unbound>(_Unbargs)...);}
};

事先保存好传入的各个参数,重载operator()操作符,生成一个_Call_front_binder:

// FUNCTION TEMPLATE _Call_front_binder
template <size_t... _Ix, class _Cv_FD, class _Cv_tuple_TiD, class... _Unbound>
constexpr auto _Call_front_binder(index_sequence<_Ix...>, _Cv_FD&& _Obj, _Cv_tuple_TiD&& _Tpl,_Unbound&&... _Unbargs) noexcept(noexcept(_STD invoke(_STD forward<_Cv_FD>(_Obj),_STD get<_Ix>(_STD forward<_Cv_tuple_TiD>(_Tpl))..., _STD forward<_Unbound>(_Unbargs)...)))-> decltype(_STD invoke(_STD forward<_Cv_FD>(_Obj), _STD get<_Ix>(_STD forward<_Cv_tuple_TiD>(_Tpl))...,_STD forward<_Unbound>(_Unbargs)...)) {return _STD invoke(_STD forward<_Cv_FD>(_Obj), _STD get<_Ix>(_STD forward<_Cv_tuple_TiD>(_Tpl))...,_STD forward<_Unbound>(_Unbargs)...);
}

走到这一步就比较熟悉了,依然是调用std::invoke实现std::bind_front的功能。

C++17之std::invoke: 使用和原理探究(全)-CSDN博客

4.注意事项

虽然std::bind_front功能超级强大,但在使用的时候,也有一些地方需要我们特别留意。

1)首先,因为它创建了新的可调用对象,多多少少会增加一点代码的复杂性,运行的时候也可能会多占点资源。特别是在那些对性能要求极高的关键代码部分,我们得好好掂量掂量,看看使用std::bind_front会不会对性能产生不好的影响。

2)其次,在绑定成员函数的时候,一定要保证绑定的类实例,在新的可调用对象的整个生命周期里都是有效的。要是不小心让类实例提前“下岗”了,那新的可调用对象在调用成员函数的时候,就会出大问题,比如空指针引用之类的错误,这可是编程中的一颗“定时炸弹”💣,千万要小心。

3)如果预先绑定的参数是大对象,并且是按值传递的,那么在创建 std::bind_front 包装器对象时会发生参数的复制,这会带来一定的性能开销。可以通过使用 std::ref 或 std::cref 按引用传递参数来避免复制。

std::ref和std::cref的使用和原理分析-CSDN博客

4)当我们使用多个std::bind_front嵌套,或者把它和其他复杂的函数对象组合在一起的时候,代码的可读性可能会大打折扣。所以,在写代码的时候,一定要尽量保持代码结构清晰明了,别为了追求功能强大,把代码搞得太复杂,到最后自己都看不懂了。

5.总结

与其他替代方案的性能比较

1. 与 std::bind 比较

  • std::bind_front 通常比 std::bind 性能更好,因为它避免了使用占位符带来的参数重排和额外的类型推导开销。std::bind 在处理复杂的参数绑定情况时,可能会生成更复杂的代码,导致性能下降。

2. 与 lambda 表达式比较

  • 简单场景:在简单的参数绑定场景下,std::bind_front 和 lambda 表达式的性能相近。编译器对两者都可以进行一定程度的优化。
  • 复杂场景:如果需要更复杂的逻辑,例如捕获多个变量、进行条件判断等,lambda 表达式可能更灵活,但也可能会引入更多的代码复杂性。而 std::bind_front 专注于参数绑定,代码相对简洁,性能可能更稳定。

总体而言,std::bind_front 在大多数情况下具有较好的性能,尤其是在简单的参数绑定场景下。但在实际使用中,还需要根据具体的可调用对象和参数情况来评估其性能。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com