Использование boost::program_options в качестве статических членов класса

По сути это следующий код, который не может пройти компилятор (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;
}

Сообщение об ошибке:

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

Любая идея?

PS Я пытаюсь определить отдельное options_description для каждой команды, которую мне нужно обработать в небольшой среде командной строки. Я использую Bison и Flex для анализа среды командной строки. Все аргументы команды будут отправлены в этот статический класс для разбора аргументов.

Поскольку определение аргумента является статическим, я не хочу превращать их в некие структуры данных в стеке (на мой взгляд, это может быть быстро и чисто). Я думаю, что этот код будет в порядке, если они не являются статичными, но что произойдет, если они будут?

3 ответа

Решение

Вам не разрешено иметь автономные операторы в глобальном масштабе или в пространстве имен.

Вы можете обойти проблему, используя возвращаемое значение расширенного add_options выражение для объявления и инициализации фиктивной переменной, как показано ниже.

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

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

Если ваша версия C++ не поддерживает auto вот так, тогда вы можете использовать полное имя типа, po::options_description_easy_initвместо.

Призыв к .add_options() это вызов функции, а не объявление. Вы пытаетесь запустить код вне функции. Попробуй это:

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

int main () {
  PopulateOptions();
}

Судя по options_description, требуется двухфазная инициализация: вызвать конструктор, а затем вызвать add_options() заселить это. Ваш код пытается выполнить второй этап вне области действия функции и завершается неудачно, потому что вызов add_options() должно быть сделано в объеме функции.

Один из способов исправить это - создать фабричную функцию, которая инициализирует и заполняет options_description объект и возвращает его. Этот возвращаемый объект можно использовать для инициализации статического экземпляра. static_class::cmd_optНапример:

// 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();

Другие варианты вместо разоблачения po::options_description статический член, выставить функцию, которая заполняет po::options_description объект передается по ссылке, например:

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 ...
}

А потом где-то в main()

po::options_description opt;
static_class::add_options(opt);
another_static_class::add_options(opt);
yet_another_static_class::add_options(opt);
Другие вопросы по тегам