Использование 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);