using boost::program_options as static members of a class

1k Views Asked by At

Basically it is the following code, which cannot pass compiler (g++)

#include <boost/program_options.hpp>
#include <iostream>
using std::cout;
using std::endl;
namespace po = boost::program_options;

class static_class {
public:
  static po::options_description cmd_opt;    // here is the definition
};

po::options_description static_class::cmd_opt("dummy");
// the line below cannot pass the compiler !!!
static_class::cmd_opt.add_options()
("help", "show usage info.")
;

main() {
  cout << static_class::cmd_opt << endl;
}

The error message:

test.cpp:16:1: error: ‘cmd_opt’ in class ‘static_class’ does not name a type

Any idea?

P.S. I am trying to define a separated options_description for each command I need to handle in a small command line environment. I am using bison and flex to parse the command line environment. All arguments of a command will be sent to this static class for argument parsing.

As the argument definition is static, I do not want to make them some sort of data structures in stack (just in my mind may be this is fast and clean). I think these code will be ok if they are not static but what happen if they are?

3

There are 3 best solutions below

2
On BEST ANSWER

You're not allowed to have standalone statements at global or namespace scope.

You could get around the issue by using the return value of the extended add_options expression to declare and initialize a dummy variable, as below.

po::options_description static_class::cmd_opt("dummy");

auto const dummy = cmd_opt.add_options()
  ("help", "show usage info.")
  ;

If your version of C++ doesn't support auto like that, then you can use the type's full name, po::options_description_easy_init, instead.

2
On

The call to .add_options() is a function call, not a declaration. You are trying to run code outside of a function. Try this:

// untested
void PopulateOptions() {
  static_class::cmd_opt.add_options()
    ("help", "show usage info.")
    ;
}

int main () {
  PopulateOptions();
}
1
On

Judging from options_description it requires a two-phase initialization: invoke the constructor and then call add_options() to populate it. Your code tries to do the second phase outside a function scope and fails because the call add_options() must be done in a function scope.

One way to fix it is to create a factory function that initializes and populates an options_description object and returns it. This return object can be used to initialize the static instance static_class::cmd_opt, e.g.:

// in .cc

namespace {

po::options_description make_options_description() {
    po::options_description opt("dummy");
    opt.add_options() // ... populate ...
    return opt;
}

}

po::options_description static_class::cmd_opt = make_options_description();

Another options is instead of exposing po::options_description static member, expose a function that populates a po::options_description object passed by reference, e.g.:

class static_class {
public:
    // requires only a forward declaration of po::options_description
    static void add_options(po::options_description&);
};

// in .cc
void static_class::add_options(po::options_description& opt) {
    opt.add_options() // ... populate ...
}

And then somewhere in main()

po::options_description opt;
static_class::add_options(opt);
another_static_class::add_options(opt);
yet_another_static_class::add_options(opt);