Boost logo

Boost Users :

Subject: [Boost-users] [program_options] Best practices, esp. for multi-app-projects?
From: Carlos Franke (carlos_franke_at_[hidden])
Date: 2011-08-02 16:27:33


I am wondering if there is a recommended way how the
boost::program_options library should be integrated in a (relatively)
complex project. To be more specific, these are my situation and my
requirements:
  â€“ A C++ project consisting of several applications, which are to
share many, but not all options.
  â€“ The interface to the options used in each app's code should be as
boost-unspecific (i. e. abstract) as possible, so that I could later
switch to another option library without having to edit much more than
one file.
  â€“ The option data should be somehow encapsulated.

After pondering on this task for quite some time, I came up with this:

  â€“ A single header file "options.h" shared by all the applications,
providing a function
    read_options(int argc, char* argv[], const po::options_description&
local_options = 0) ,
which scans the command line and the usual configuration files* for
the common options (which are defined in the same header file, of
course) as well asoptional app-specific options, and saves them (next
paragraph).
*(There is of course the problem of each app's name being part of its
config-file's name. I found a solution for this, but I am not sure if
it is relevant here. Or is it?)

  â€“ Regarding the encapsulation, I found any kind of class or struct
containing the options (possibly with get and set methods) unsuitable
or overkill, as I would have to deal with instantiation and possible
problems of multiple instantiation (singleton?). Also, I did not feel
the need for the security provided by get and set methods. So what I
did is: put all option variables in one namespace, like this:
    namespace options
    {
       int option1;
       std::string option2;
       ///...
    }
A namespace has the further great advantage of being extendable after
creation. Programme-specific options can be added easily.

So in the end, in each programme I only have to do:
    //optional: define local options
    namespace options
    { /* . . . */ }
    po::options_description my_options
    /* . . . */ ;
    //read and save options:
    options::read_options(argc, argv, my_options)
    //from now on access the options' values by
    //options::option1;

As I see it, this approach has only two drawbacks:
  â€“ In each programme's code I have to deal with options twice: 1)
declare the storage variables in the options namespace (globally); 2)
declare local options_description and call read_options (in the main
function).
  â€“ There is no way to tell if the option variables are in a valid
state, unless one is sure that read_options has been called and has set
all values (at least to valid default values).
I am inclined to tolerate the first issue and resolve the second by:
  â€“ not using "default_value" in any po::options_description
  â€“ instead intializing the option variables with their default values.
That way, at any time each option variable either stores its default
value or the assigned to it from the command line or a configuration
file.

Oh my, that ended up much longer than I expected. Those of you who read
this far: What are your thoughts about using boost::program_options in
general and about my particular approach?

Regards!

Carlos Franke



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net