收藏 分销(赏)

BOOST应用初探.doc

上传人:pc****0 文档编号:7993875 上传时间:2025-01-30 格式:DOC 页数:74 大小:608KB 下载积分:10 金币
下载 相关 举报
BOOST应用初探.doc_第1页
第1页 / 共74页
BOOST应用初探.doc_第2页
第2页 / 共74页


点击查看更多>>
资源描述
BOOST应用初探 作者:冯刚 2011-8-4 1 背景 BOOST是由c++标准化委员会成员参与开发的c++标准的准官方库,他是C++标准库的发动机。下一代C++标准C++0x的标准库很多来自于boost。Boost库覆盖了广泛的领域,从数学库到智能指针,从模板元编程库到预处理器库及语法词法分析,从线程到lambda表达式,等等。所有Boost库都具有宽松的许可证,确保库可以被自由使用于商用软件。 2 功能 2.1 概况 Boost库涵盖了很广泛的领域,下面就常用的功能像智能指针,正则表达式,函数对象bind和function, 线程和线程池,时间日期,多索引容器,哈希容器,bimap,日志,内存池,模板元编程,循环缓冲区,tuple, 观察者模式signal2,网络通讯asio做一些介绍。 2.2 功能 2.2.1 智能指针 2.2.1.1 概论 smart pointers(智能指针)是存储“指向动态分配(在堆上)的对象的指针”的对象。他们的行为很像 C++ 的内建指针,只是它们可以在适当的时候自动删除它们所指向的对象。智能指针在面对异常时有非常显著的作用,它们可以确保动态分配对象的完全析构。它们还可以用于跟踪多主人共享的动态分配对象。 在概念上,智能指针可以看作拥有它所指向的对象,并因此在对象不再需要时负责将它删除。 智能指针库提供了六个智能指针类模板: scoped_ptr <boost/scoped_ptr.hpp> 简单的单一对象的唯一所有权。不可拷贝。 scoped_array <boost/scoped_array.hpp> 简单的数组的唯一所有权。不可拷贝。 shared_ptr <boost/shared_ptr.hpp> 在多个指针间共享的对象所有权。 shared_array <boost/shared_array.hpp> 在多个指针间共享的数组所有权。 weak_ptr <boost/weak_ptr.hpp> 一个属于 shared_ptr 的对象的无所有权的观察者。 intrusive_ptr <boost/intrusive_ptr.hpp> 带有一个侵入式引用计数的对象的共享所有权。 这些模板被设计用来补充 std::auto_ptr 模板的不足。 2.2.1.2 智能指针shared_ptr shared_ptr 类模板存储一个指向动态分配对象(一般是用 C++ new-expression 生成的)的指针。在最后一个 shared_ptr 所指向的对象被销毁或重置时,要保证它所指向的对象被删除。 每一个 shared_ptr 都符合 C++ 标准库的 CopyConstructible 和 Assignable 的必要条件,并因此能够用于标准库容器。因为提供了比较操作,因此 shared_ptr 可以和标准库中的关联式容器一起工作。 通常,一个 shared_ptr 不能正确地持有一个指向动态分配的数组的指针。关于那种用法请参见 shared_array。 因为在实现中使用了引用计数,shared_ptr实例的循环引用不会被回收。例如,如果 main() 持有一个指向 A 的 shared_ptr, A 又直接或间接持有一个指回 A 的 shared_ptr,A 的使用计数是 2。最初的 shared_ptr 析构后将导致一个使用计数为 1 的 A 被悬挂。使用 weak_ptr 以“打破循环”。 这个类模板被 T 参数化,T 是被指向的对象的类型。shared_ptr 和它的大多数成员函数对于 T 没什么要求,允许它是一个不完整类型,或者为 void。对 T 有附加要求的成员函数 (constructors, reset) 都明确地记录在下面。 只要 T* 能被隐式地转换到 U*,则 shared_ptr<T> 就能被隐式地转换到 shared_ptr<U>。特别是,shared_ptr<T> 隐式转换到 shared_ptr<T const>,当 U 是 T 的一个可访问基类的时候,还能转换到 shared_ptr<U>,以及转换到 shared_ptr<void>。 惯用手法 由于智能指针是线程安全的,建议在代码里只为一个对象生成单一的shared_ptr,在多线程环境中传递参数时使用weak_ptr,这样当shared_ptr被析构,weak_ptr也会得到通知,变为无效,这样可以有效地防止野指针,同时也防止了潜在的循环引用,无法释放对象的问题。 shared_ptr<A> spA = shared_ptr<A>(new A); int func(weak_ptr<A> wpA) { If(!wpA.expired()) { //正常处理逻辑 shared_ptr<A> spA = wpA.lock(); //Use spA } else { //智能指针已被其他线程释放 } } func(spA); 2.2.1.3 智能指针weak_ptr 简介 weak_ptr是Boost智能指针shared_ptr的一个重要伙伴。它允许打破循环依赖。另外,它还可以处理一个非常常见的问题—悬空指针。当销毁最后一个智能指针shared_ptr,它会释放掉共享的资源。通过使用智能指针weak_ptr,这方面的信息会传播给所有观察该共享资源的智能指针weak_ptr,通过weak_ptr可以知道该共享资源已经释放,这意味着不会发生无意间访问无效指针的情形。这就是观察者模式的一个特例,也就是说,当销毁资源的时候,就会通知所有对资源感兴趣的weak_ptr,通过调用weak_ptr.expired(),当返回值为true时,就表示该共享资源已经释放了。 weak_ptr 类模板存储一个引向已被 shared_ptr 管理的对象的 "weak reference"(弱引用)。为了访问这个对象,一个 weak_ptr 可以利用 shared_ptr 的构造函数或成员函数 lock 转换为 shared_ptr。当最后一个指向对象的 shared_ptr 消失,而对象也被删除后,从一个引向已被删除对象的 weak_ptr 实例获取 shared_ptr 的企图就会失败:构造函数会抛出一个 boost::bad_weak_ptr 类型的异常,而 weak_ptr::lock 会返回一个 empty shared_ptr。 每一个 weak_ptr 都符合 C++ 标准库的 CopyConstructible 和 Assignable 的必要条件,并因此能够用于标准库容器。因为提供了比较操作,因此 weak_ptr 可以和标准库中的关联式容器一起工作。 weak_ptr 的操作绝不会抛出异常。 这个类模板被 T 参数化,T 是被指向的对象的类型。 相对于 shared_ptr,weak_ptr 提供了一个非常有限的操作子集,因为在多线程程序中访问它所存储的指针是非常危险的,甚至有时在一个单线程程序中也是不安全的(也就是说,它可能引起未定义行为)。姑且假设 weak_ptr 有一个返回 raw pointer(裸指针)的 get 成员函数,考虑下面这个无辜的代码片段: shared_ptr<int> p(new int(5)); weak_ptr<int> q(p); // some time later if(int * r = q.get()) { // use *r } 设想在 if 之后,但是又恰恰在 r 被使用之前,另一个线程执行了语句 p.reset()。这样 r 就成了一个 dangling pointer(悬挂指针)。 解决这个问题的方案是从 q 创建一个临时的 shared_ptr: shared_ptr<int> p(new int(5)); weak_ptr<int> q(p); // some time later if(shared_ptr<int> r = q.lock()) { // use *r } 这样,r 就持有一个引向 q 所指向的对象的引用。即使在其它线程中执行了 p.reset(),那个对象也会继续活着,直到 r 离开作用域或者被 reset。通过获得一个指向这个对象的 shared_ptr,我们可以有效地保住它不被析构。 2.2.2 正则表达式 xpressive 是一个先进的、面向对象的、用于C++的正则表达式模板库。正则表达式可以以字符串方式编写并在运行期分析,也可以以表达式模板方式编写并在编译期分析。正则表达式可以相互引用,或者递归引用其本身,你就可以用它们来构建任意复杂的语法。它与Boost.Regex库的区别就是无需编译,全模板库。 如果你要在C++中处理文本,通常你有两个不相交的选项:正则表达式引擎或语法分析生成器。正则表达式引擎(如 Boost.Regex)更为强大和灵活;文本的模式以字符串方式表示,可以在运行期指定。但是,这意味着语法错误同样要到运行期才能被检测。另外,正则表达式不适合于高级的文本处理任务,如匹配平衡的、嵌套的标签。那些任务传统上都是由语法分析生成器(如 Spirit 语法分析器框架)来处理的。这些工具更为强大,但不够灵活。它们通常不允许你随时随意地修改你的语法规则。此外,它们不具备正则表达式的完全回溯语义,对于某些类型的模式来说,这样对作者更具有挑战性。 将这两种方法无缝地集合到一起,在C++的文本处理世界中占据了独特的优势。通过 xpressive,你可以选择更象使用 Boost.Regex 那样去使用它,将正则表达式表示为字符串。或者你也可以象使用 Spirit 那样使用它,将你的 regexes 写为C++表达式,获得一种专用于文本处理的嵌入式语言所带来的所有好处。更重要的是,你可以混用这两种方式,从而获得两者的好处,对于那些要静态绑定的正则表达式编写正则表达式语法  -- 由编译器进行硬编码和语法检查 -- 其它的则动态绑定并在运行期指定。这些正则表达式可以相互递归地引用,在以前的正则表达式不能进行模式匹配的字符串中进行模式匹配。 Xpressive 是一个只含头文件的模板库,这意味着你不需要修改你的构建脚本或链接任何独立的lib文件就可以使用它。你所要做的就是 #include <boost/xpressive/xpressive.hpp>。如果你只使用静态 regexes,你可以只包含 xpressive_static.hpp 以提高编译速度。同样,如果你计划只使用动态regexes,则可以只包含 xpressive_dynamic.hpp。 表 28.1. xpressive的工具箱 Tool 工具 Description 说明 basic_regex<> 含有一个已编译的正则表达式。basic_regex<> 是xpressive之中最重要的类型。你用xpressive做的任何事情都要从创建一个类型为 basic_regex<> 的对象开始。 match_results<>, sub_match<> match_results<> 含有 regex_match() 或 regex_search() 操作的结果。它就象一个存有 sub_match<> 对象的向量。一个 sub_match<> 对象含有一个已标记的子表达式(在Perl中又称为后向引用)。基本上,它只是一个迭代器对,代表了已标记子表达式的开始和结束。 regex_match() 检查一个字符串是否匹配一个regex。regex_match() 要成功,必须是整个字符串从头到尾匹配regex。如果你给了 regex_match() 一个 match_results<>,那么它会将所有找到的带标记子表达式写入其中。 regex_search() 查找一个字符串,以发现其中匹配regex的子字符串。regex_search() 将尝试在字符串的每个位置查找匹配,从头部开始,当找到一个匹配或者整个字符串找完时停止。使用 regex_match() 时,如果你给了 regex_search() 一个 match_results<>,那么它会将所有找到的带标记子表达式写入其中。 regex_replace() 给定一个输入字符串,一个regex和一个替代字符串,regex_replace() 通过将输入字符串中与regex相匹配的部分替换为替代字符串来构建一个新的字符串。替代字符串可以含有对带标记子表达式的引用。 regex_iterator<> 一个与STL兼容的迭代器,可以很方便地找到在一个字符串中与某个regex匹配的所有地方。解引用一个 regex_iterator<> 会返回一个 match_results<>。递增一个 regex_iterator<> 可以找出下一个匹配。 regex_token_iterator<> 类似于 regex_iterator<>,除了一点,解引用一个 regex_token_iterator<> 会返回一个字符串。缺省地,它返回与regex匹配的整个子字符串,不过它也可以被配置为每次返回任一个或整个带标记子表达式,或者甚至是不匹配 regex的部分字符串。 regex_compiler<> 一个用于 basic_regex<> 对象的工厂。它将一个字符串"编译"为正则表达式。通常,你不需要直接关心 regex_compiler<>,因为 basic_regex<> 类有一个工厂方法,其内部使用了 regex_compiler<>。不过,如果你需要做一些花哨的东西,如创建一个带有不同 std::locale 的 basic_regex<> 对象,你就需要显式使用 regex_compiler<> 了。  现在你应该对xpressive所提供的工具有了一些了解,你可以通过回答以下两个问题来找到合适的工具: 1. 你要用哪种类型的迭代器来遍历你的数据? 2. 你要对你的数据做什么操作? 弄明白你的迭代器类型 在xpressive中的多数类都是根据迭代器类型参数化的模板类。xpressive定义了一些常用的typedefs来让你可以更容易地选择合适的类型。你可以用下表基于你的迭代器类型来找到正确的类型。 下表 为 xpressive Typedefs 与迭代器类型 std::string::const_iterator char const * std::wstring::const_iterator wchar_t const * basic_regex<> sregex cregex wsregex wcregex match_results<> smatch cmatch wsmatch wcmatch regex_compiler<> sregex_compiler cregex_compiler wsregex_compiler wcregex_compiler regex_iterator<> sregex_iterator cregex_iterator wsregex_iterator wcregex_iterator regex_token_iterator<> sregex_token_iterator cregex_token_iterator wsregex_token_iterator wcregex_token_iterator 你要留意系统的命名习惯。这些类型经常要一起使用,所以命名习惯可以帮助你一致地使用它们。例如,如果你有一个 sregex,你就应该使用 smatch。 如果你用的不是以上四种迭代器类型之一,那么你可以直接用模板并指定你的迭代器类型。 示例 以下你将看到六个完整的示例程序。   检查整个字符串是否匹配一个regex 这是来自于"简介"一节中的示例。为便于查看,在此重复。 #include <iostream> #include <boost/xpressive/xpressive.hpp> using namespace boost::xpressive; int main() { std::string hello( "hello world!" ); sregex rex = sregex::compile( "(\\w+) (\\w+)!" ); smatch what; if( regex_match( hello, what, rex ) ) { std::cout << what[0] << '\n'; // whole match 整个匹配 std::cout << what[1] << '\n'; // first capture 第一次捕获 std::cout << what[2] << '\n'; // second capture 第二次捕获 } return 0; } 程序输出如下: hello world! hello world 检查一个字符串是否包含匹配某个regex的子串 请留意在这个例子中,我们是如何使用定制的 mark_tags 来使得匹配的模式更可读。我们可以在稍后使用 mark_tags 来对 match_results<> 进行索引访问。 #include <iostream> #include <boost/xpressive/xpressive.hpp> using namespace boost::xpressive; int main() { char const *str = "I was born on 5/30/1973 at 7am."; // 以名字定义一些定制的 mark_tags,比 s1, s2 等更有意义。 mark_tag day(1), month(2), year(3), delim(4); //该regex查找一个日期 cregex date = (month= repeat<1,2>(_d)) // 查找月份... >> (delim= (set= '/','-')) // 后跟一个分隔符... >> (day= repeat<1,2>(_d)) >> delim // 和一个日期再跟一个分隔符... >> (year= repeat<1,2>(_d >> _d)); //和年份。 cmatch what; if( regex_search( str, what, date ) ) { std::cout << what[0] << '\n'; // whole match 全匹配 std::cout << what[day] << '\n'; // the day 日期 std::cout << what[month] << '\n'; // the month 月份 std::cout << what[year] << '\n'; // the year 年份 std::cout << what[delim] << '\n'; // the delimiter 分隔符 } return 0; } This program outputs the following: 程序输出如下: 5/30/1973 30 5 1973 / 替换匹配某个regex的所有子串 以下程序在一个字符串中查找日期并用伪-HTML标记它们。 #include <iostream> #include <boost/xpressive/xpressive.hpp> using namespace boost::xpressive; int main() { std::string str( "I was born on 5/30/1973 at 7am." ); // 基本上与上一个例子中的regex相同,但用的是动态regex sregex date = sregex::compile( "(\\d{1,2})([/-])(\\d{1,2})\\2((?:\\d{2}){1,2})" ); // 和在Perl中一样,$& 是指向匹配该regex的子串的引用 std::string format( "<date>$&</date>" ); str = regex_replace( str, date, format ); std::cout << str << '\n'; return 0; } 程序输出如下: I was born on <date>5/30/1973</date> at 7am. 查找匹配某个regex的所有子串并每次一个地分步处理它们 以下程序在一个宽字符串中查找单词。它使用 wsregex_iterator。注意,对 wsregex_iterator 的解引用将产生一个 wsmatch 对象。 #include <iostream> #include <boost/xpressive/xpressive.hpp> using namespace boost::xpressive; int main() { std::wstring str( L"This is his face." ); //查找一个完整的单词 wsregex token = +alnum; wsregex_iterator cur( str.begin(), str.end(), token ); wsregex_iterator end; for( ; cur != end; ++cur ) { wsmatch const &what = *cur; std::wcout << what[0] << L'\n'; } return 0; } 程序输出如下: This is his face 将字符串分拆为匹配某个regex的记号 以下程序在字符串中查找比赛时间,并且先显示分钟数再显示秒数。它使用 regex_token_iterator<>. #include <iostream> #include <boost/xpressive/xpressive.hpp> using namespace boost::xpressive; int main() { std::string str( "Eric: 4:40, Karl: 3:35, Francesca: 2:32" ); //查找比赛时间 sregex time = sregex::compile( "(\\d):(\\d\\d)" ); // 对于每个匹配,记号迭代器首先取出第一个被标记的子表达式的值,然后是第二个子表达式的值 int const subs[] = { 1, 2 }; sregex_token_iterator cur( str.begin(), str.end(), time, subs ); sregex_token_iterator end; for( ; cur != end; ++cur ) { std::cout << *cur << '\n'; } return 0; } This program outputs the following: 程序输出如下: 4 40 3 35 2 32 用一个regex作为分隔符分拆字符串 以下程序接受一些带有html标记的文本,去掉其中的标记。它使用一个regex来匹配HTML标签,并用一个 regex_token_iterator<> 返回字符串中不匹配该regex的其余部分。 #include <iostream> #include <boost/xpressive/xpressive.hpp> using namespace boost::xpressive; int main() { std::string str( "Now <bold>is the time <i>for all good men</i> to come to the aid of their</bold> country." ); // find a HTML tag 查找一个HTML标签 sregex html = '<' >> optional('/') >> +_w >> '>'; // 以下的 -1 指示记号迭代器显示字符串中不匹配正则表达式的部分。 sregex_token_iterator cur( str.begin(), str.end(), html, -1 ); sregex_token_iterator end; for( ; cur != end; ++cur ) { std::cout << '{' << *cur << '}'; } std::cout << '\n'; return 0; } 程序输出如下: {Now }{is the time }{for all good men}{ to come to the aid of their}{ country.} 显示嵌套结果组成的树 以下是一个辅助类,示范了如何显示由嵌套结果组成的树: //以缩入方式将嵌套结果输出至 std::cout struct output_nested_results { int tabs_; output_nested_results( int tabs = 0 ) : tabs_( tabs ) { } template< typename BidiIterT > void operator ()( match_results< BidiIterT > const &what ) const { //首先进行缩入 typedef typename std::iterator_traits< BidiIterT >::value_type char_type; char_type space_ch = char_type(' '); std::fill_n( std::ostream_iterator<char_type>( std::cout ), tabs_ * 4, space_ch ); //输出匹配结果 std::cout << what[0] << '\n'; //输出嵌套的匹配 std::for_each( what.nested_results().begin(), what.nested_results().end(), output_nested_results( tabs_ + 1 ) ); } }; 2.2.3 Bind 目的 boost::bind 是标准函数 std::bind1st 和 std::bind2nd 的泛化。它支持任意的函数对象,函数,函数指针,和成员函数指针,它还能将任何参数绑定为一个特定的值,或者将输入的参数发送到任意的位置。bind 对函数对象没有任何要求,特别是,它不需要 result_type,first_argument_type 和 second_argument_type 这样的标准 typedefs。 int f(int a, int b) { return a + b; } int g(int a, int b, int c) { return a + b + c; } bind(f, 1, 2) 会产生一个“无参数”函数对象,它不需要参数并返回 f(1, 2)。同样,bind(g, 1, 2, 3)() 等价于 g(1, 2, 3)。 有选择性地只绑定一部分参数也是有可能的。bind(f, _1, 5)(x) 等价于 f(x, 5),这里,_1 是一个占位符参数,它的含义是“用第一个输入参数取代”。 bind 能够处理带有两个以上参数的函数,而且它的参数取代机制更为直观: bind(f, _2, _1)(x, y); // f(y, x) bind(g, _1, 9, _1)(x); // g(x, 9, x) bind(g, _3, _3, _3)(x, y, z); // g(z, z, z) bind(g, _1, _1, _1)(x, y, z); // g(x, x, x) 注意,最后一个示例中,由 bind(g, _1, _1, _1) 生成的函数对象不包含对第一个参数以外的任何参数的引用,但是它仍然能使用一个以上的参数。所有多余的参数被悄悄地忽略,就像在第三个示例中,第一和第二个参数被忽略。 bind 持有的参数被返回的函数对象拷贝并内部持有。例如,在下面的代码中: int i = 5; bind(f, i, _1); 一个 i 的值的拷贝被存储于函数对象中。boost::ref 和 boost::cref 可用于让函数对象存储一个引用而不是拷贝: int i = 5; bind(f, ref(i), _1); bind(f, cref(42), _1); (和函数对象一起使用 bind) bind 并不限于函数,它可以接受任何函数对象。通常情况下,生成的函数对象的 operator() 的返回类型必须显式指定(没有 typeof 操作符,返回类型无法推导): struct F { int operator()(int a, int b) { return a - b; } bool operator()(long a, long b) { return a == b; } }; F f; int x = 104; bind<int>(f, _1, _1)(x); // f(x, x), i.e. zero 有些编译器遇到 bind<R>(f, ...) 语法会发生问题。出于可移植性的原因,一种和上面的意思相同的可选的表达方式也被支持: boost::bind(boost::type<int>(), f, _1, _1)(x); 但是要注意,这种可选语法只是作为一个 workaround 提供。它不是接口的一部分。 当函数对象暴露了一个名为 result_type 的内嵌类型时,显式返回类型可以被省略: int x = 8; bind(std::less<int>(), _1, 9)(x); // x < 9 【注意:这种省略返回类型的能力并非在所有的编译器上都可用。】 缺省情况下,bind 为提供的函数对象做出一份拷贝。boost::ref 和 boost::cref 可用于让它存储这个函数对象的引用,而非拷贝。当函数对象是不可拷贝的,拷贝代价高昂,或者包含状态时是很有用的,当然,在这种情况下,要求程序员确保这个函数对象在使用期间不能被销毁。 struct F2 { int s; typedef void result_type; void operator()( int x ) { s += x; } }; F2 f2 = { 0 }; int a[] = { 1, 2, 3 }; std::for_each( a, a+3, bind( ref(f2), _1 ) ); assert( f2.s == 6 ); (和成员指针一起使用 bind) 成员函数的指针和数据成员的指针不是函数对象,因为它们不支持 operator()。为了方便起见,bind 接受成员指针作为它的第一个参数,而它的行为就像使用 boost::mem_fn 将成员指针转换成一个函数对象一样。换句话说,当 R 是 X::f 的返回类型(作为成员函数)或成员本身的类型(作为数据成员)时,表达式 bind(&X::f, args) 与 bind<R>(mem_fn(&X::f), args) 等价。 【注意:mem_fn 创建的函数对象可以接受一个对象的指针,引用或智能指针作为它的第一个参数,更多的信息,参见 mem_fn 文档。】 示例: struct X { bool f(int a); }; X x; shared_ptr<X> p(new X); int i = 5; bind(&X::f, ref(x), _1)(i); // x.f(i) bind(&X::f, &x, _1)(i); //(&x)->f(i) bind(&X::f, x, _1)(i); // (internal copy of x).f(i) bind(&X::f, p, _1)(i); // (internal copy of p)->f(i) 最后两个示例的有趣之处在于它们生成“自包含”的函数对象。bind(&X::f, x, _1) 存储 x 的一个拷贝。bind(&X::f, p, _1) 存储 p 的一个拷贝,而且因为 p 是一个 boost::shared_ptr,这个函数对象保存一个属于它自己的 X 的实例的引用,而且当 p 离开它的作用域或者被 reset() 之后,这个引用依然保持有效。 (为函数组合使用嵌套的 binds) 传给 bind 的某些参数可以嵌套 bind 表达式自身: bind(f, bind(g, _1))(x); // f(g(x)) 当函数对象被调用的时候,如果没有指定顺序,内部 bind 表达式先于外部 bind 表达式被求值,在外部 bind 表达式被求值的时候,用内部表达式的求值结果取代它们的占位符的位置。在上面的示例中,当用参数列表 (x) 调用那个函数对象的时候,bind(g, _1)(x) 首先被求值,生成 g(x),然后 bind(f, g(x))(x) 被求值,生成最终结果 f(g(x))。 bind 的这个特性可被用来执行函数组合。参见示例 bind_as_compose.cpp,示范如何用 bind 达到与 Boost.Compose 类似的功能。 注意第一个参数——被绑定函数对象——是不被求值的,即使它是一个由 bind 生成的函数对象或一个占位符参数,所以下面的示例不会如你所愿地工作: typedef void (*pf)(int); std::vector<pf> v; std::for_each(v.begin(), v.end(), bind(_1, 5)); 你所要的效果,可以通过将一个辅助函数对象 apply 用作它的第一个参数而获得,作为一个函数对象,它可以支撑它的参数列表。为了方便起见,在 boost/bind/apply.hpp 头文件中提供了一个 apply 的
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 百科休闲 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服