//Using boost program options to read command line and config file data
#include <boost/program_options.hpp>
using namespace std;
using namespace boost;
namespace po = boost::program_options;
int main (int argc, char *argv[])
{
po::options_description config("Configuration");
config.add_options()
("IPAddress,i","IP Address")
("Port,p","Port")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, config),vm);
po::notify(vm);
cout << "Values\n";
string address = (vm["IPAddress"].as<std::string >()).c_str();
string port = (vm["Port"].as<std::string>()).c_str();
cout << (vm["IPAddress"].as< string >()).c_str();
cout << " " << (vm["Port"].as<string>()).c_str();
return 0;
}
Are the inputted values somehow unprintable?
Here is gdb output, seems to be be cast problem:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl
' what(): boost::bad_any_cast: failed conversion using boost::any_cast
Program received signal SIGABRT, Aborted. 0x0000003afd835935 in raise () from /lib64/libc.so.6
string address = (vm["IPAddress"].as<std::string >()).c_str();
is where the error occurs; I have tried std::string and string with the same results.
testboostpo -i 192.168.1.10 -p 5000
is the command line.
I tried declaring the types, like so:
config.add_options()
("IPAddress,i", po::value<std::string>(), "IP Address")
("Port,p", po::value<std::string>(), "Port");
but the error still occurred.
Could this be a genuine bug?
Not necessarily the same problem as this guy had but here's something that caught me:
If you put your type in an anonymous namespace, there will be two classes with the same name but different instances and the casting will fail. For example:
a.hpp:
b.cpp:
c.cpp:
It fails because the
MyClass
inb.cpp
and the one inc.cpp
aren't the same class. Because of the anonymous namespace.Removing the anonymous namespace solves the problem.
You need to declare the ip-address and port as strings when you add the options:
This same message can also occur if you are not handling optional arguments correctly.
Sam's solution nails required arguments and the OP's code suggests required - just mark them required. For optional inputs, the Boost PO tutorial gives us a template for checking if the option exists before converting it:
My problem - I had copied/pasted and forgotten to align the if test with the usage!
You see the
boost::bad_any_cast
exception thrown from thepo::variables_map
because the twoconst char*
argument overload ofpo::options_description_easy_init::operator()
does not specify apo::value_semantic
type, so converting it to astd::string
will not work. If you want to convert the value to astd::string
, and it is required for your application, use therequired()
value semantic.Note the added catch block since parsing can (and will, as you have noticed) throw exceptions. Here is a sample session:
Here is an online demo showing the same behavior, courtesy of COmpile LInk RUn (coliru).