问题
Let's say I would like special processing for integer options. According to the documentation I have to write my own validate function. Consider the following short program.
#include <iostream>
#include <vector>
#include <string>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
namespace boost { namespace program_options {
template <class charT>
void validate(boost::any& v, const std::vector<std::basic_string<charT> >& xs, unsigned int*, int)
{
std::cout << "validate is redefined" << std::endl;
// do something else
}
}}
int main(int argc, char* argv[])
{
po::options_description cmdLineOptions;
po::variables_map vm;
unsigned int v;
const char* args[] = {"tst", "-k", "10"};
cmdLineOptions.add_options()
("key,k", po::value<unsigned int>(&v)->required())
;
po::store(po::command_line_parser(sizeof(args) / sizeof(args[0]), args).options(cmdLineOptions).run(), vm);
po::notify(vm);
std::cout << v << '\n';
return 0;
}
It perfectly works in VS 2013 and outputs
validate is redefined
10
In GCC it never steps inside the validate function.
Proof: http://coliru.stacked-crooked.com/a/fd558ebf987a4bbe
If I try to use a custom type instead of unsigned int, GCC would try to use a validate from program_option anyway and will end up with bunch of errors.
What I am doing wrong?
回答1:
On a preliminary hunch, consider using
BOOST_STRONG_TYPEDEF(unsigned int, Unsigned);
It seems like a bad idea to customize behaviour just on built-in types.
Solution: It has to do with partial ordering.
If you move your overload outside the boost::program_options
namespace it will start working (as it no longer competes with the base template).
Live On Coliru
#include <iostream>
#include <vector>
#include <string>
#include <boost/any.hpp>
#include <boost/serialization/strong_typedef.hpp>
#include <boost/program_options.hpp>
BOOST_STRONG_TYPEDEF(unsigned, Unsigned)
template<class charT>
void validate(boost::any& v,
const std::vector< std::basic_string<charT> >& xs,
Unsigned* p, int)
{
std::cout << "validate is redefined" << std::endl;
// do something else
}
namespace po = boost::program_options;
int main()
{
po::options_description cmdLineOptions;
po::variables_map vm;
Unsigned v;
const char* args[] = {"tst", "-k", "10"};
cmdLineOptions.add_options()
("key,k", po::value<Unsigned>(&v)->required())
;
po::store(po::command_line_parser(sizeof(args) / sizeof(args[0]), args).options(cmdLineOptions).run(), vm);
po::notify(vm);
std::cout << v << '\n';
return 0;
}
The cause is likely MSVC's famously broken 2-phase lookup
- Two phase lookup - explanation needed
来源:https://stackoverflow.com/questions/27072129/custom-validator-for-boost-program-options-doesnt-work-with-gcc-works-with-msv