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
Rob Kennedy 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
Robᵩ 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
Maxim Egorushkin 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);