Boost 库中的实用工具类使用入门

Boost库是一个非常强大的C++库,其中包含了很多数据结构、算法和工具函数 在boost::graph中,boost::sequential_vertex_coloring是一个用于解决顶点着色问题的算法。这个测试程序创建了一个无向图G,并添加了4条边。然后,它调用了boost::sequential_vertex_coloring算法来对G中的顶点进行着色。总的来说,boost::sequential_vertex_coloring是一个快速而简单的算法,可以被用于许多不同的场合。其中,boost::graph是用来处理图形数据结构的一个模块,其中包含了许多基本算法和数据结构。 阅读详情

级别: 中级

Arpan Sen, 首席工程师, IBM

2008 年 9 月 08 日

实用工具类开发和维护会耗费程序员的时间。Boost 通过提供几个高质量的库,从而简化了此过程,您可以将这些库轻松集成到现有的代码库中。本文简单概述一些较流行的 Boost 实用工具类,并帮助您了解如何将它们投入使用。

实用工具类(utility classes)在几乎任何适当规模的 C++ 项目中都是必需的,但是不存在满足此需求的标准方法。通常,团队根据他们的需求编写实用工具类代码,但是由于缺少重要的接口信息,使得相同组织中的其他项目团队无法重用那些类。建议的标准模板库(Standard Template Library,STL)只具有诸如 hash、stack 和 vector 等少数基本类,因此无法有效地用于取代遗留实用工具库。

本文将介绍几个 Boost 实用工具类,包括 tuple、static_assert、pool、random 和 program_options。您需要对标准 STL 具备一定的了解才能充分理解本文的内容。本文中的所有代码都已使用 Boost 1.35 来进行了测试并使用 gcc-3.4.4 来进行了编译。

boost::tuple 类

有时,您希望 C++ 函数返回多个不相关的值。在推出 STL 之前,实现此目的的方法是创建所有不相关变量的结构,并以指针或引用的形式返回它们或作为参数传递给函数——但是任一种方法都不是表达程序员意图的方法。STL 引入了 pair,可将其用于聚合不相关的数据部分,但它一次只能处理两个数据对象。为了使用 int、char 和 float 的元组(tuple ),您可以按如下方式返回 pair:

make_pair<int, pair<char, float> > (3, make_pair<char, float> ('a', 0.9));
			

随着您添加更多的元素,创建元组结构将变得越来越困难。Boost tuple 类型派上了用场。要使用 boost::tuple,您必须包括头文件 tuple.hpp。要执行元组比较和元组 I/O,您需要分别包括 tuple_comparison.hpp 和 tuple_io.hpp。

第一个使用元组的程序

清单 1 使用 int、char 和 float 的元组并打印内容。


清单 1. 创建 Boost 元组并打印内容
                
#include <iostream>
#include <tuple.hpp>
#include <tuple_comparison.hpp>
#include <tuple_io.hpp>
using namespace boost;

int main ( )
  {
  tuple<int, char, float> t(2, 'a', 0.9);
  std::cout << t << std::endl;
  return 0;
  }
		  

此代码的输出为 (2 a 0.9)。请注意,<< 运算符重载 std::ostream,以便通过转储每个单独的 tuple 元素来输出元组。

与元组相关的重要事实

在使用元组时,务必牢记以下事实:

  • 能够形成元组的元素数量目前仅限于 10 个。
  • 元组可以包含用户定义的类类型,但是您必须负责确保那些类已经定义了正确的构造函数和拷贝构造函数 (copy constructor)。清单 2 显示了产生编译时错误的代码部分,因为该拷贝构造函数是私有的。

    清单 2. 用于元组的类必须具有正确的拷贝构造函数
                            
    #include <tuple.hpp>
    #include <tuple_comparison.hpp>
    #include <tuple_io.hpp>
    #include <iostream>
    using namespace std;
    
    class X
      {
      int x;
      X(const X& u) { x = u.x; }
      public:
        X(int y=5) : x(y) { }
      };
    
    int main ( )
      {
      boost::tuple<int, X> t(3, X(2));
      return 0;
      }
    		  

  • 与 STL 提供的 make_pair 函数非常类似,Boost 提供了 make_tuple 例程。要从函数返回元组,您必须调用 make_tuple。可以创建具有临时元素的元组;清单 3 的输出为 (4 0)。

    清单 3.使用 make_tuple 来从函数返回元组
                            
    #include <tuple.hpp>
    #include <tuple_comparison.hpp>
    #include <tuple_io.hpp>
    #include <iostream>
    using namespace std;
    
    boost::tuple<int, int>
    divide_and_modulo(int a, int b)
      {
      return boost::make_tuple<int, int> (a/b, a%b);
      }
    
    int main ( )
      {
      boost::tuple<int, int> t = divide_and_modulo(8, 2);
      cout << t << endl;
      return 0;
      }
    		  		  

  • 要访问元组的各个元素,您可以使用 get 例程。此例程具有两种变体,如清单 4 所示。请注意,还可以使用 get 例程来设置元组的各个元素,虽然有些编译器可能不支持此功能。

    清单 4. 使用 boost::get 例程
                            
    #include <tuple.hpp>
    #include <tuple_comparison.hpp>
    #include <tuple_io.hpp>
    #include <iostream>
    using namespace std;
    
    boost::tuple<int, int>
    divide_and_modulo(int a, int b)
      {
      return boost::make_tuple<int, int> (a/b, a%b);
      }
    
    int main ( )
      {
      boost::tuple<int, int> t = divide_and_modulo(8, 2);
      cout << t.get<0>() << endl; // prints 4
      cout << boost::get<1>(t) << endl; // prints 0
    
      boost::get<0>(t) = 9; // resets element 0 of t to 9
      ++boost::get<0>(t);   // increments element 0 of t
      cout << t.get<1>() << endl; // prints 10
      return 0;
      }

  • 可以使用 const 限定符来声明元组,在这种情况下,用于访问特定元素的 get 调用将返回对 const 的引用。不能对以这种方式访问的元素进行赋值(请参见清单 5)。

    清单 5. 使用 const 限定符来声明的元组不可修改
                            
    #include <tuple.hpp>
    #include <tuple_comparison.hpp>
    #include <tuple_io.hpp>
    #include <iostream>
    using namespace std;
    
    int main ( )
      {
      const boost::tuple<int, char*> t(8, "Hello World!");
      t.get<1>()[0] = "Y"; // error!
      boost::get<0>(t) = 9; // error!
      return 0;
      }

  • 可以使用关系运算符 ==、!=、<、>、<= 和 >= 对相同长度的元组进行比较。比较不同长度的元组会产生编译时错误。这些运算符的工作原理是从左到右地比较两个参与元组的每个单独的元素(请参见清单 6)。

    清单 6. 关系运算符与元组
                            
    #include <tuple.hpp>
    #include <tuple_comparison.hpp>
    #include <tuple_io.hpp>
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main ( )
      {
      boost::tuple<int, string> t(8, string("Hello World!"));
      boost::tuple<int, string> t2(8, string("Hello World!"));
      cout << (t == t2) << endl;
    
      boost::tuple<int, string> r(9, string("Hello World!"));
      boost::tuple<int, string> r2(8, string("Hello World!"));
      cout << (r > r2) << endl;
    
      boost::tuple<string, string> q(string("AA"), string("BB"));
      boost::tuple<string, string> q2(string("AA"), string("CC"));
      cout << (q < q2) << endl;
    
      return 0;
      }

    清单 6 的输出为 1 1 1。请注意,如果您不是使用 string 或 int,而是使用没有定义 ==、!= 等运算符的用户定义的随机类,则会产生编译错误。




回页首


Boost 静态断言

断言是 C/C++ 中的防错性程序设计的一部分。最常见的用法如下:

assert(<some expression you expect to be true at this point in code>);
		    

assert 例程仅在调试模式下有效。在发布模式下,通常使用预处理器宏 ¨CDNDEBUG 来编译代码,其效果相当于 assert 不存在。静态断言建立在这个基本概念之上,只不过静态断言仅在编译时有效。此外,静态断言不生成任何代码。

例如,假设您在一个整型变量中执行某个位操作,并预期其大小为 4:这并非在所有操作系统平台上都是如此(请参见清单 7)。


清单 7. 使用 Boost 静态断言来验证变量的大小
                
#include <boost/static_assert.hpp>
int main ( )
  {
  BOOST_STATIC_ASSERT(sizeof(int) == 4);
   // … other code goes here
  return 0;
  }
		  

要使用 BOOST_STATIC_ASSERT 宏,您必须包括 static_assert.hpp 头文件。不需要诸如 DNDEBUG 等特定于编译器的选项,并且您不需要向链接器提供库——单凭该头文件就足够了。

如果断言有效,则代码将顺利编译。但是如果该假设无效,在某些 64 位平台上就可能是如此,则编译器将生成错误消息并停止。使用 g++-3.4.4 进行编译时的典型消息如下:

assert.cc: In function `int main()':
assert.cc:8: error: incomplete type `boost::STATIC_ASSERTION_FAILURE< false>' 
    used in nested name specifier
		  		  

这肯定不是最详细的错误消息,但是它指出了具有错误假设的函数和确切行号。

下面是一些典型的现实情景,您应该在其中考虑使用静态断言:

  • 静态声明的数组的边界检查
  • 验证原始和用户定义的变量的大小
  • 允许模板类或函数仅使用某些数据类型来进行实例化

Boost 静态断言的行为

您可以在类、函数或命名空间范围中使用 Boost 静态断言;还可以与模板一起使用它们。清单 8 中的示例阐明了概念。


清单 8. 使用 Boost 静态断言来限制类实例化
                
#include <iostream>
#include <static_assert.hpp>
using namespace std;
using namespace boost;

template<class T>
class A
  {
  private:
    T x, y;
    BOOST_STATIC_ASSERT(numeric_limits<T>::is_signed);
  public:
    A(T x1, T y1) : x(x1), y(y1) { }
  };

int main ( )
  {
  A<unsigned long> a(2, 1);
  return 0;
  }
		  

在清单 8 中,仅当 T 有符号时,模板类 A 才能进行实例化。类 numeric_limits 是标准命名空间的一部分;它检查基本类型在给定操作系统平台上的属性。在无符号(unsigned )的 long 类型的情况下,专用变体 numeric_limits<unsigned int> 的 is_signed 标志为 false。当您在类范围中使用 BOOST_STATIC_ASSERT 时,它是私有的、受保护的还是公开的并不重要。

清单 9 将 BOOST_STATIC_ASSERT 与函数结合在一起使用。该代码确保在函数 f1 中处理的类型只能是 A 类型或其派生类型。通过使用 Boost 的静态断言宏和 is_convertible 例程(在 boost/type_traits/is_convertible.hpp 中定义),此代码确保不希望的类型不会最终调用此例程。


清单 9. 将函数限制为仅处理特定的数据类型
                
#include <iostream>
#include <static_assert.hpp>
#include <boost/type_traits/is_convertible.hpp>
using namespace std;
using namespace boost;

struct A
  {
  int a;
  float b;
  };

struct B : public A
  {
  };

template <typename T>
int f1 (T y)
  {
  BOOST_STATIC_ASSERT((is_convertible<T, A*>::value));
  return 0;
  }

int main ( )
  {
  f1<B*> (new B);
  return 0;
  }
  





回页首


使用 Boost 库生成随机数

随机数生成用于各种各样的计算机应用,例如安全和游戏。UNIX 系统一般附带了随机数生成例程 rand 和 srand。通常,srand 使用新的种子值来初始化 rand(请参见清单 10)。


清单 10. 用于在传统 UNIX 中生成随机数的代码
                
#include <stdlib.h>
#include <stdio.h>

int main ( )
  {
  srand(time(NULL)); // this introduces randomness
  for (int i=0; i<10; i++)
    printf("%d/n", rand());
  return 0;
  }
		  		  		  

rand 例程返回一个介于 0 和 stdlib.h 中定义的 RAND_MAX 之间的数字。要了解 srand 所做的工作,可以在将 srand 例程注释掉的情况下编译清单 11。当您这样做时,您将观察到 rand 并不真正是随机的——可执行代码每次打印同一组值。为了在代码中引入随机性,您可以使用 srand,此例程使用种子值来初始化 rand。由于每次调用程序时的时间值是不同的,因此对于不同的调用,代码打印的值不同。

传统随机数生成器的问题
传统随机数生成器具有几个问题。它们无法生成在用户指定范围内均匀分布的随机数,或者符合高斯或二项式分布的随机数。本文仅在可将随机数映射到某个范围内的上下文中讨论随机数。

使用 Boost 随机数生成器

Boost 随机数生成器位于 boost/random 文件夹中。此外,为方便起见,boost/ 目录中的 random.hpp 头文件包括了 boost/random 文件夹中的所有其他头文件。

Boost 随机接口划分为两个部分:随机数生成器和随机数必须位于其中的分布。本文讨论 uniform_int 和 uniform_real random-number 分布以及 mt19937 随机数生成器。清单 11 使用了 uniform_int 和 uniform_real 分布。


清单 11. 将 variate_generator 与 mt19937 引擎和 uniform_int 分布一起使用
                
#include <iostream>
#include <boost/random.hpp>
using namespace std;
using namespace boost;

int main ( )
  {
  uniform_int<> distribution(1, 100) ;
  mt19937 engine ;
  variate_generator<mt19937, uniform_int<> > myrandom (engine, distribution);

  for (int i=0; i<100; ++i)
    cout << myrandom() << endl;

  return 0;
  }

此代码生成介于 1 和 100 之间(包括 1 和 100)的随机数;用于实现随机化的基础引擎是 mt19937。variate_generator 为您组合了该引擎和分布。

清单 12 使用了另一个引擎: kreutzer1986.


清单 12:组合 uniform_real 分布和 kreutzer1986 引擎
                
#include <iostream>
#include <boost/random.hpp>
using namespace std;
using namespace boost;

int main ( )
  {
  uniform_real<> distribution(1, 2) ;
  kreutzer1986 engine ;
  variate_generator<kreutzer1986, uniform_real<> > myrandom (engine, distribution);

  for (int i=0; i<100; ++i)
    cout << myrandom() << endl;

  return 0;
  }
		  

除了 uniform_int 和 uniform_real 分布以外,Boost 还提供了几个其他分布,包括二项式、泊松和正态分布。





回页首


boost::pool 库概述

Boost pool 库引入了可用于实现快速内存分配的工具。正确的内存块对齐可以得到保证。

根据 Boost 文档所述,当您分配和释放许多小型对象时,建议使用池。使用池的另一个不太明显的优点在于,作为程序员,您不必担心内存泄露:内存由 Boost 库在内部自动进行管理。要使用 pool 库,您不必在链接时提供特定的库——单凭头文件就足以完成链接了。

有多个接口对 pool 库可用:

  • 池接口——替代 malloc 进行工作的普通接口。要使用此接口,需要包括 boost/pool 文件夹中的 pool.hpp 头文件。
  • 对象池接口——有对象意识的接口,在对象创建和删除过程中分别相应地调用构造函数和析构函数。还可以使用此接口创建普通对象,而不调用它们的构造函数。接口定义是在位于 boost/pool 目录中的 object_pool.hpp 头文件中提供的。清单 13 引入了 pool 和 object_pool 接口。请注意以下几点:
    • pool 接口需要知道每个单独的元素而不是类型的大小,因为它是一个 malloc 风格的分配程序,不会调用构造函数。
    • pool 接口中的 malloc 例程返回 void*。
    • object-pool 接口需要类型信息,因为要调用构造函数。
    • object-pool 接口中的 malloc/construct 例程返回指向类型的指针。malloc 例程不调用构造函数,但是 construct 要调用构造函数。
    • 使用 pool 接口或 object-pool 接口来创建的元素的范围与从中创建它们的池的范围相同。
    • 要从池接口中释放内存,可以调用 purge_memory 方法。该方法释放您先前创建的内存块,并使得从分配程序例程返回的所有指针失效。
    • 要释放各个元素,可以调用 pool 接口中的 free 例程。例如,如果 t 是使用 pool 接口来创建的池,并且 m 是从 t 分配的指针,则 t.free(m) 将把内存返回给 t(将其添加到 t 的空闲内存列表)。

      清单 13. pool 和 object_pool 接口
                                  
      #include <iostream>
      #include <boost/pool/pool.hpp>
      #include <boost/pool/object_pool.hpp>
      using namespace std;
      using namespace boost;
      
      class A
        {
        public: A( ) { cout << "Declaring A/n"; }
               ~A( ) { cout << "Deleting A/n"; }
        };
      
      int main ( )
        {
        cout << "Init pool.../n";
      
        pool<> p(10 * sizeof(A));
        for (int i=0; i<10; ++i)
          A* a = (A*) p.malloc(); // Always returns sizeof(A)
        p.purge_memory();
      
        cout << "Init object pool.../n";
      
        object_pool<A> q;
        for (int i=0; i<10; ++i)
          A* a = q.construct(); // Calls A's constructor 10 times
      
        return 0;
        }
        

  • singleton_pool 接口——与 pool 接口几乎相同,但是用作独立池。独立池的底层结构具有为 malloc、free 等声明的静态成员函数,并且构造函数是私有的。独立池声明中的第一个参数称为标记——它允许存在不同的独立池集(例如,用于 int 的多个池,其中每个池服务于不同的目的)。必须包括 singleton_pool.hpp 头文件才能使用此接口。请参见清单 14。

    清单 14. singleton_pool 接口
                            
    #include <iostream>
    #include <boost/pool/singleton_pool.hpp>
    using namespace std;
    using namespace boost;
    
    struct intpool {  };
    struct intpool2 {  };
    
    typedef boost::singleton_pool<intpool, sizeof(int)> ipool1;
    typedef boost::singleton_pool<intpool2, sizeof(int)> ipool2;
    
    int main ( )
      {
      cout << "Init singleton pool.../n";
      for (int i=0; i<10; ++i) {
        int* q1 = (int*) ipool1::malloc();
        int* q2 = (int*) ipool2::malloc();
      }
    
      ipool1::purge_memory();
      ipool2::purge_memory();
      return 0;
      }
    		  

  • pool_alloc 接口——通常与 STL 容器结合在一起使用。请考虑以下代码片段:
    #include <boost/pool/pool_alloc.hpp>
    
    std::vector<int, boost::pool_allocator<int> > v;
    std::list<double, boost::fast_pool_allocator<double> > L;
    

    存在两个分配程序:pool_allocator 和 fast_pool_allocator。第一个分配程序是通用分配,可以满足针对任何数量的连续内存块的请求。fast_pool_allocator 最适合于一次请求单个(通常较大)块,但是也适用于通用分配,不过具有一些性能缺点。




回页首


boost::program_options 简介

命令行处理是另一个难点,开发人员通常不会采用结构化的方式来解决。其结果是从头到尾维护开销。Boost program_options 库提供了简化命令行处理的例程和数据结构。

清单 15 详细描述了 boost::program_options 的使用。这是建议在您的代码中使用的标准模板。


清单 15. 使用 boost::program_options
                
#include <string>
#include <iostream>
#include <boost/program_options.hpp>
using namespace std;

int main (int ac, char* av[])
  {
  boost::program_options::options_description options("command line options");
  options.add_options() ("help", "Use -h or --help to list all arguments")
                                      ("file", boost::program_options::value<string>(),
                                       "Provide input file name");
  boost::program_options::variables_map vmap;
  boost::program_options::store(
      boost::program_options::parse_command_line(ac, av, options), vmap);
  boost::program_options::notify(vmap);

  if (vmap.count("help")) {
      cout << options << endl;
  }

  return 0;
  }
		  

您必须包括 program_options.hpp 头文件。清单 15 的工作方式如下:

  1. options_description 类声明所有的有效命令行选项。
  2. 使用方法 add_options,您可以注册命令和跟在命令后面的参数类型。在此例中,help 选项不需要任何参数,但是 file 选项需要一个字符串参数。
  3. variables_map 类在运行时存储命令行选项及其参数。
  4. Boost 的 parse_command_line 例程解析 argc 和 argv 参数。store 和 notify 方法帮助存储 vmap 对象中的数据。
  5. 当您检查 help 是否为程序的恰当命令行选项(这是 vmap.count("help") 所做的工作)时,options 对象将被转储到 cout。这意味着运算符 << 是为 options_description 类定义的。

下面是来自清单 15 的输出:

[user@/home/user1] ./a.out --help
command line options:
  --help                Use -h or --help to list all arguments
  --file arg            Provide input file name
  

当您遇到其他选项时,可以采取进一步的操作。例如,下面的代码片段经过了修改,以打印您输入的文件名:

…
if (vmap.count("file")) {
     cout << "Setting input file to " << vmap["file"].as<string>() << "./n";
 } else {
     cout << "No file specified/n";
 }
…

请注意,variable_map 类在许多方面与哈希表非常相似。例如,要检索 file 参数,您可以调用 vmap["file"]。





回页首


提供多个参数和缩写的命令选项

命令行处理通常同时需要同一个命令选项的短名称和长名称。此外,您通常必须多次使用某个选项,以便收集该选项的所有参数。例如,您可能希望使用 ¨Ch 和 ¨Chelp 来打印可用的命令。清单 16 演示了这些功能。


清单 16. 使用较短的选项变体并允许多次调用命令选项
                
#include <string>
#include <iostream>
#include <boost/program_options.hpp>
using namespace std;

int main (int ac, char* av[])
  {
  boost::program_options::options_description options("command line options");
  options.add_options() ("help,h", "Use -h or --help to list all arguments")
                    ("file", boost::program_options::value<vector<string> >( ),
                         "Provide input file name");
  boost::program_options::variables_map vmap;
  boost::program_options::store(
      boost::program_options::parse_command_line(ac, av, options), vmap);
  boost::program_options::notify(vmap);

  if (vmap.count("help")) {
      cout << options << endl;
  }

  if (vmap.count("file")) {
      vector<string> ifiles(vmap["file"].as< vector<string> > ());
      vector<string>::iterator vI;
      cout << "Number of input files: " << ifiles.size() << endl;
      cout << "Input file list: " << endl;
      for(vI = ifiles.begin(); vI != ifiles.end(); ++vI)
          cout << "/t" << *vI << endl;
  } else {
      cout << "No file specified/n";
  }

  return 0;
  }
		  

在使用 add_options 来添加命令选项时,较长和较短的选项之间使用逗号进行分隔。请注意,较长的选项 (help) 必须在较短的选项 (h) 之前,代码才能正常工作。与使用单个字符串不同,file 选项现在是使用一个字符串向量来定义的。如果指定了 ¨Cfile 选项多次,则会将在所有指定中收集到的命令选项参数存储在关联的 vector<string> 中。下面是使用不同的参数来多次指定 ¨Ch 和 ¨Cfile 所获得的输出:

[user@/home/user1] ./a.out -h
command line options:
  -h [ --help ]         Use -h or --help to list all arguments
  --file arg            Provide input file name

No file specified
[user@/home/user1] ./a.out --file abc --file pqr
Number of input files: 2
Input file list:
        abc
        pqr





回页首


解析位置选项

带输入参数但是不带命令行选项来调用某个程序是非常普遍的。您预期参数和命令行选项之间自动存在某种神奇关联。这种行为由 boost::program_options 提供支持。

请考虑清单 17。第一个参数转换为 --file=<first parameter>,第二个参数转换为 --do-file=<second parameter>。


清单 17. 将位置参数与命令行选项相关联
                
#include <string>
#include <iostream>
#include <boost/program_options.hpp>
using namespace std;

int main (int ac, char* av[])
  {
  boost::program_options::options_description options("command line options");
  options.add_options() ("help,h", "Use -h or --help to list all arguments")
                        ("file", boost::program_options::value<string>(),
                         "Provide input file name")
                        ("do-file", boost::program_options::value<string>(),
                         "Specify commands file");

  boost::program_options::variables_map vmap;
  boost::program_options::positional_options_description poptd;
  poptd.add("file", 1);
  poptd.add("do-file", 2);

  boost::program_options::store(
      boost::program_options::command_line_parser(ac, av).
      options(options).positional(poptd).run(), vmap);
  boost::program_options::notify(vmap);

  if (vmap.count("file")) {
     cout << "file: " << vmap["file"].as<string> ( ) << endl;
  }

  if (vmap.count("do-file")) {
     cout << "do-file: " << vmap["do-file"].as<string> ( ) << endl;
  }

  return 0;
  }
		  

下面是输出内容:

[user@/home/user1] ./a.out file1 dofile1
file: file1
do-file: dofile1

清单 15 中使用的某些 API 在清单 17 中已发生更改。清单 17 引入了新的类 positional_options_description。该类的 add 方法(add("command option", N))将位置 N 处的输入参数与命令行选项 "command option" 相关联。因此,./a.out file1 在内部解析为 ./a.out ¨Cfile=file1。另一个区别在于调用 program_options::store 方法的方式。与使用 parse_command_line 例程不同,Boost 库要求您将 command_line_parser 例程与 store 方法结合在一起使用。

请注意,仍然可以使用 ¨Cfile 和 ¨Cdo-file 选项来调用该程序。最后,若要将所有的输入参数与同一个命令行选项相关联,您需要使用值 -1 将该命令行选项添加到 positional_options_description 对象。下面是代码:

…
boost::program_options::positional_options_description poptd;
poptd.add("file", -1);
...





回页首


结束语

本文提供了 Boost 库中较为有用的一些实用工具类的概述。只要使用得当,它们可以为您省去大量的代码维护开销。鉴于所讨论的概念的范围和广度,论及每个实用工具类的每个功能是不切实际的。参考资料部分提供了进一步的阅读参考。



参考资料

学习

获得产品和技术

讨论


关于作者

Arpan Sen 是致力于电子设计自动化行业的软件开发首席工程师。他使用各种 UNIX 版本(包括 Solaris、SunOS、HP-UX、IRIX,以及 Linux 和 Microsoft Windows)已经多年。他热衷于各种软件性能优化技术、图形理论和并行计算。Arpan 获得了软件系统硕士学位。

Boost库中的is_convertible是一个非常有用的模板元函数,用于确定参数类型之间是否可以进行隐式转换 在上面的代码中,我们使用了std::boolalpha来设置输出格式,使得输出的结果为true/false而不是1/0。这表明,我们将int类型隐式转换为double类型是不可能的,但是我们可以将double类型隐式转换为int类型,并且对于const int&和int类型的转换,也是可以进行隐式转换的。本文提供的《is_convertible相关的测试程序》是一个简单而实用的示例,希望读者可以通过阅读本文和运行示例程序加深对is_convertible的理解。 阅读详情

相关推荐

C++ boost库教程(一):boost简介

C++ boost零基础教程

琅嬛福地 5万+

boost I 操作系统相关的库(三)- program_options系统

目录 一、基本流程 二、组件介绍 1.选项描述器 (1)value_semantic选项值 (2)option_description (3)options_description 2.分析器 (1)parse_command_line (2)parse_config_file (3)parse_environment 3.存储器 三、扩展 1.位置选项值 2.未知选项 3.命令行风格 program_options 库提供了从外界获取程序选项的能力。程序的选...

该用户还没想到好的昵称的博客 2609

BEVFusion实战:从零搭建LiDAR-Camera融合的3D目标检测环境(附避坑指南)

本文提供了BEVFusion实战指南,详细讲解如何从零搭建LiDAR-Camera融合的3D目标检测环境。内容涵盖环境配置、数据预处理、模型训练与性能优化等关键步骤,并附有实用的避坑技巧,帮助开发者高效部署这一先进的BEV感知算法。

p4q5r6s7t的博客 514

boost::program_options

作用: 它是一个C++解析命令行的库。它使用命令行和配置文件对程序选项进行设置。该库有错误检查机制,它的选项值可从命令行,配置文件以及环境变量中提取。 要解析一个命令行选项,需要以下三步: 1.定义命令行选项。取名且设置值。若一个命令行选项解析为键/值对,还需要设置值的类型,比如是一个字符串还是一个数字 2.用解析器去解析命令行。从main()的两个参数中获取命令行,argc与argv

x-2010的笔记 1577

从零到一:高通Memory QMVS测试环境搭建的避坑指南

本文详细介绍了高通Memory QMVS测试环境搭建的全流程避坑指南,涵盖硬件选择、软件配置、QMVS核心组件安装及测试执行技巧。重点解析了adb工具配置、QPST日志抓取等关键步骤,帮助工程师高效搭建稳定测试环境,避免常见兼容性和稳定性问题。

weixin_29251567的博客 555

优化求解器性能:当分支切割算法中的gap停滞不前时如何应对

本文深入探讨了当分支切割算法求解复杂整数规划问题时,gap停滞不前的根本原因与应对策略。文章指出gap停滞源于上界(找不到更优整数解)或下界(证明过程缓慢)提升受阻,并提供了从模型改写、自定义割平面、调整搜索策略到参数调优等一系列实战方法,帮助优化工程师有效打破求解僵局,推动gap下降。

weixin_29294597的博客 381

深入浅出boost::program_options ,命令行或配置文件读取参数选项

boost::program_options 用法详解简介Boost 是一个有着高质量、高性能、高可靠性的 C++工具库,地位仅次于 C++ 的标准库。是否掌握 Boost 已经成为很多优秀公司面试 C++工程师的基本要求。Boost.Program_options 在实际的开发应用中使用广泛。本次课程将通过实例系统讲解 如何使用 Boost.Program_options 解析参数,环境变量以及...

卢克治-BJTU-NLP-的博客 1523

Pytorch实现EdgeCNN(基于PyTorch实现)

本专栏整理了《图神经网络代码实战》,内包含了不同图神经网络的相关代码实现(PyG以及自实现),理论与实践相结合,如GCN、GAT、GraphSAGE等经典图网络,每一个代码实例都附带有完整的代码。

优快云 精品推荐 1万+

Boost 库中的实用工具类使用入门——boost and STL

实用工具类(utility classes)在几乎任何适当规模的 C++ 项目中都是必需的,但是不存在满足此需求的标准方法。通常,团队根据他们的需求编写实用工具类代码,但是由于缺少重要的接口信息,使得相同组织中的其他项目团队无法重用那些类。建议的标准模板库(Standard Template Library,STL)只具有诸如 hash、stack 和 vector 等少数

thiwind的专栏 1404

【QNX Hypervisor 2.2 用户手册】2.6 处理qvm终止

你可以注册通知,以在qvm进程实例退出时得到通知。这样你就可以采取相应的措施来响应这种终止事件。

从0到1,突破自己 1106

基于YOLO26的实时目标追踪实战:从训练到视频追踪(附完整可视化代码)

核心组合:YOLO26(高精度检测)+ ByteTrack(稳定追踪)是实时目标追踪的最优工业组合,Ultralytics内置集成无需额外开发;训练优化:追踪场景需优先提升检测框精度(增加box损失权重),保证ID稳定性;可视化核心:为每个ID分配唯一颜色、绘制运动轨迹、显示FPS,是落地场景的必备功能;性能调优:轻量化模型+降分辨率+OpenVINO导出,可在边缘设备(如研华工控机)实现实时追踪。这套代码可直接复用到智慧园区、停车场、工业产线等场景,仅需修改park.yaml中的类别和。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 571

Boost库中的实用工具类使用入门

简介:实用工具类开发和维护会耗费程序员的时间。Boost 通过提供几个高质量的库,从而简化了此 过程,您可以将这些库轻松集成到现有的代码库中。本文简单概述一些较流行的 Boost 实用工具类,并 帮助您了解如何将它们投入使用。 实用工具类(utility classes)在几乎任何适当规模的 C++ 项目中都是必需的,但是不存在满足此 需求的标准方法。通常,团队根据他们的需求编写实用工具类代码,

hbyzl的专栏 406

YOLOv11改进入门篇 | 手把手讲解改进模块如何实现高效涨点,以SimAM注意力模块为例

本文记录的是基于SimAM注意力模块的YOLOv11目标检测方法研究。SimAM注意力模块通过优化能量函数来获得每个神经元的三维权重,而或增加计算复杂度。若是有轻量化需求的小伙伴,无参的注意力模块也许是一个不错的选择。

Limiiiing的博客 9036
上一篇: 图像识别技术突破成功,发文庆贺!
下一篇: 仅通过崩溃地址找出源代码的出错行
521
521
博客等级 码龄26年 10粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值