提升程序选项和shared_ptr

时间:2014-03-18 02:44:52

标签: c++ boost shared-ptr boost-program-options

我正在尝试使用类来动态组合不同应用程序的程序选项。当使用desc的普通指针时,一切正常。在下面的shared_ptr情况下,解析器无法识别添加的程序选项。

我错过了什么?

非常感谢。

namespace config = boost::program_options;

class Parser {

public:

  Parser();

  void add_all();
  void add_x_options();
  void add_y_options();
  void add_z_options();

  void parse(int argc, char** argv);

  std::shared_ptr<boost::program_options::options_description> desc;

};


Parser::Parser() {
  desc = std::shared_ptr<boost::program_options::options_description>(new boost::program_options::options_description("Options"));
}


void Parser::add_x_options() {
  ...
  desc->add_options()
    ("option1", config::value<std::string>()->required())
    ("option2", config::value<std::string>()->required());
}

void Parser::parse(int argc, char** argv) {
  config::variables_map vmap;

  try {
    config::store(config::parse_command_line(argc, argv, *desc), vmap);

    if (vmap.count("help")) {
      std::cout << *desc << std::endl;
      return false;
    }

    vmap.notify();
  }
  catch(std::exception& e) {
    std::cout << "Error message.\n";
    return false;
  }
  return true;
}

1 个答案:

答案 0 :(得分:1)

我不知道你错过了什么,但它可能不在显示的代码中。除非您实际忘记及时致电add_x_options()

这是我的测试计划:看到 Live On Coliru

int main()
{
    do_test({ "--help" });
    do_test({ "--option1" });
    do_test({ "--option1", "value1" });
    do_test({ "--option2", "value2" });
    do_test({ "--option1", "value1", "--option2", "value2" });
}

哪些输出(我在add_x_options中添加了--help选项,因此可以对其进行测试):

---------------------------------------------------------------------------
Test: fake_program.exe --help 
without add_x_options: Error message: unrecognised option '--help'
after add_x_options: Options:
  --help                print usage instructions
  --option1 arg
  --option2 arg

---------------------------------------------------------------------------
Test: fake_program.exe --option1 
without add_x_options: Error message: unrecognised option '--option1'
after add_x_options: Error message: the required argument for option '--option1' is missing
---------------------------------------------------------------------------
Test: fake_program.exe --option1 value1 
without add_x_options: Error message: unrecognised option '--option1'
after add_x_options: Error message: the option '--option2' is required but missing
---------------------------------------------------------------------------
Test: fake_program.exe --option2 value2 
without add_x_options: Error message: unrecognised option '--option2'
after add_x_options: Error message: the option '--option1' is required but missing
---------------------------------------------------------------------------
Test: fake_program.exe --option1 value1 --option2 value2 
without add_x_options: Error message: unrecognised option '--option1'
after add_x_options: 

完整代码

#include <boost/program_options.hpp>
#include <boost/config.hpp>
#include <memory>
#include <iostream>

class Parser {
    public:
        Parser();
        void add_all();
        void add_x_options();
        void add_y_options();
        void add_z_options();
        bool parse(int argc, char** argv);
    private:
        std::shared_ptr<boost::program_options::options_description> desc;
};


Parser::Parser() {
    desc = std::shared_ptr<boost::program_options::options_description>(new boost::program_options::options_description("Options"));
}

namespace config = boost::program_options;

void Parser::add_x_options() {
    //...
    desc->add_options()
        ("help",    "print usage instructions")
        ("option1", config::value<std::string>()->required())
        ("option2", config::value<std::string>()->required());
}

bool Parser::parse(int argc, char** argv) {
    config::variables_map vmap;

    try {
        config::store(config::parse_command_line(argc, argv, *desc), vmap);

        if (vmap.count("help")) {
            std::cout << *desc << std::endl;
            return false;
        }

        vmap.notify();
        return true;
    }
    catch(std::exception& e) {
        std::cout << "Error message: " << e.what() << "\n";
        return false;
    }
}

void do_test(std::initializer_list<const char*> args)
{
    std::string fake_program = "fake_program.exe";
    std::vector<char*> fake_argv { &fake_program[0] };
    for(auto&& arg : args)
        fake_argv.push_back(const_cast<char*>(arg));

    Parser parser;

    std::cout << "---------------------------------------------------------------------------\n";
    std::cout << "Test: ";
    for(auto const& a : fake_argv)
        std::cout << a << " ";
    std::cout << "\n";

    std::cout << "without add_x_options: ";
    parser.parse(fake_argv.size(), fake_argv.data());

    std::cout << "after add_x_options: ";
    parser.add_x_options();
    parser.parse(fake_argv.size(), fake_argv.data());
}

int main()
{
    do_test({ "--help" });
    do_test({ "--option1" });
    do_test({ "--option1", "value1" });
    do_test({ "--option2", "value2" });
    do_test({ "--option1", "value1", "--option2", "value2" });
}