Book Image

Boost C++ Application Development Cookbook - Second Edition

By : Anton Polukhin Alekseevic
Book Image

Boost C++ Application Development Cookbook - Second Edition

By: Anton Polukhin Alekseevic

Overview of this book

If you want to take advantage of the real power of Boost and C++ and avoid the confusion about which library to use in which situation, then this book is for you. Beginning with the basics of Boost C++, you will move on to learn how the Boost libraries simplify application development. You will learn to convert data such as string to numbers, numbers to string, numbers to numbers and more. Managing resources will become a piece of cake. You’ll see what kind of work can be done at compile time and what Boost containers can do. You will learn everything for the development of high quality fast and portable applications. Write a program once and then you can use it on Linux, Windows, MacOS, Android operating systems. From manipulating images to graphs, directories, timers, files, networking – everyone will find an interesting topic. Be sure that knowledge from this book won’t get outdated, as more and more Boost libraries become part of the C++ Standard.
Table of Contents (19 chapters)
Title Page
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Getting configuration options


Take a look at some of the console programs, such as cp in Linux. They all have a fancy help; their input parameters do not depend on any position and have a human-readable syntax. For example:

$ cp --help
Usage: cp [OPTION]... [-T] SOURCE DEST
  -a, --archive           same as -dR --preserve=all
  -b                      like --backup but does not accept an argument

You can implement the same functionality for your program in 10 minutes. All you need is the Boost.ProgramOptions library.

Getting ready

Basic knowledge of C++ is all you need for this recipe. Remember that this library is not only a header, so your program has to link against the libboost_program_options library.

How to do it...

Let's start with a simple program that accepts the count of apples and oranges as input and counts the total number of fruits. We want to achieve the following result:

$ ./our_program.exe --apples=10 --oranges=20
Fruits count: 30

Perform the following steps:

  1. Include the boost/program_options.hpp header and make an alias for the boost::program_options namespace (it is too long to type it!). We would also need an <iostream> header:
#include <boost/program_options.hpp> 
#include <iostream> 

namespace opt = boost::program_options; 
  1. Now, we are ready to describe our options in the main() function:
int main(int argc, char *argv[])
{
    // Constructing an options describing variable and giving 
    // it a textual description "All options". 
    opt::options_description desc("All options"); 

    // When we are adding options, first parameter is a name
    // to be used in command line. Second parameter is a type
    // of that option, wrapped in value<> class. Third parameter
    // must be a short description of that option.
    desc.add_options()
        ("apples", opt::value<int>(), "how many apples do 
                                       you have")
        ("oranges", opt::value<int>(), "how many oranges do you 
                                        have")
        ("help", "produce help message")
    ;
  1. Let's parse the command line:
    // Variable to store our command line arguments.
    opt::variables_map vm; 

    // Parsing and storing arguments.
    opt::store(opt::parse_command_line(argc, argv, desc), vm); 

    // Must be called after all the parsing and storing.
    opt::notify(vm);
  1. Let's add some code for processing the help option:
    if (vm.count("help")) {
        std::cout << desc << "\n";
        return 1;
    }
  1. Final step. Counting fruits may be implemented in the following way:
    std::cout << "Fruits count: "
        << vm["apples"].as<int>() + vm["oranges"].as<int>()
        << std::endl;

} // end of `main`

Now, if we call our program with the help parameter, we'll get the following output:

All options: 
--apples arg          how many apples do you have
--oranges arg        how many oranges do you have 
--help                    produce help message 

As you can see, we do not provide a type for the help option's value, because we do not expect any values to be passed to it.

How it works...

This example is pretty simple to understand from code and comments. Running it produces the expected result:

$ ./our_program.exe --apples=100 --oranges=20
Fruits count: 120

There's more...

The C++ standard adopted many Boost libraries; however, you won't find Boost.ProgramOptions even in C++17. Currently, there's no plan to adopt it into C++2a.

The ProgramOptions library is very powerful and has many features. Here's how to:

  • Parse configuration option values directly into a variable and make that option a required one:
    int oranges_var = 0;
    desc.add_options()
        // ProgramOptions stores the option value into 
        // the variable that is passed by pointer. Here value of 
        // "--oranges" option will be stored into 'oranges_var'.
        ("oranges,o", opt::value<int>(&oranges_var)->required(), 
                                                "oranges you have")
  • Get some mandatory string option:
        // 'name' option is not marked with 'required()',
        // so user may not provide it.
        ("name", opt::value<std::string>(), "your name")
  • Add short name for apple, set 10 as a default value for apples:
        // 'a' is a short option name for apples. Use as '-a 10'.
        // If no value provided, then the default value is used.
        ("apples,a", opt::value<int>()->default_value(10),
                                   "apples that you have");
  • Get the missing options from the configuration file:
    opt::variables_map vm;

    // Parsing command line options and storing values to 'vm'.
    opt::store(opt::parse_command_line(argc, argv, desc), vm);

    // We can also parse environment variables. Just use
    // 'opt::store with' 'opt::parse_environment' function.

    // Adding missing options from "apples_oranges.cfg" config file.
    try {
        opt::store(
            opt::parse_config_file<char>("apples_oranges.cfg", desc),
            vm
        );
    } catch (const opt::reading_file& e) {
        std::cout << "Error: " << e.what() << std::endl;
    }

Note

The configuration file syntax differs from the command-line syntax. We do not need to place minuses before the options. So, our apples_oranges.cfg file must look like this:oranges=20

  • Validate that all the required options were set:
    try {
        // `opt::required_option` exception is thrown if
        // one of the required options was not set.
        opt::notify(vm);

    } catch (const opt::required_option& e) {
        std::cout << "Error: " << e.what() << std::endl;
        return 2;
    }

If we combine all the mentioned tips into a single executable, then its help command will produce this output:

$ ./our_program.exe --help
 All options:
   -o [ --oranges ] arg          oranges that you have
   --name arg                       your name
   -a [ --apples ] arg (=10)  apples that you have
   --help                              produce help message

Running it without a configuration file will produce the following output:

$ ./our_program.exe
 Error: can not read options configuration file 'apples_oranges.cfg'
 Error: the option '--oranges' is required but missing 

Running the program with oranges=20 in the configuration file will generate ++, because the default value for apples is 10:

$ ./our_program.exe
 Fruits count: 30

See also