在命名空间中使用 boost::program_options::validate 和自己的 class
Using boost::program_options::validate with own class in namespace
如果 magic_number
不在命名空间中,以下改编示例将编译,但如果它在命名空间中,则会失败。
如果目标 class 在命名空间中,为什么找不到 validate
函数?
MSVC 上产生的错误是:
converter_lexical.hpp(243): error C2338: Target type is neither
std::istream'able nor std::wistream'able.
我在使用 Clang here 时遇到了同样的错误。
进行测试; comment/uncomment #define USE_NAMESPACE
:
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// This example shows how a user-defined class can be parsed using
// specific mechanism -- not the iostream operations used by default.
//
// A new class 'magic_number' is defined and the 'validate' method is overloaded
// to validate the values of that class using Boost.Regex.
// To test, run
//
// regex -m 123-456
// regex -m 123-4567
//
// The first invocation should output:
//
// The magic is "456"
//
// and the second invocation should issue an error message.
#include <boost/program_options.hpp>
#include <boost/regex.hpp>
#include <iostream>
namespace po = boost::program_options;
//#define USE_NAMESPACE
#ifdef USE_NAMESPACE
namespace ns1{
#endif
/* Define a completely non-sensical class. */
struct magic_number {
public:
magic_number(int n) : n(n) {}
magic_number() = default;
int n;
};
#ifdef USE_NAMESPACE
}
#endif
/* Overload the 'validate' function for the user-defined class.
It makes sure that value is of form XXX-XXX
where X are digits and converts the second group to an integer.
This has no practical meaning, meant only to show how
regex can be used to validate values.
*/
#ifdef USE_NAMESPACE
void validate(boost::any& v, const std::vector<std::string>& values,
ns1::magic_number*, int)
#else
void validate(boost::any& v, const std::vector<std::string>& values,
magic_number*, int)
#endif
{
static boost::regex r("\d\d\d-(\d\d\d)");
// Make sure no previous assignment to 'a' was made.
po::validators::check_first_occurrence(v);
// Extract the first string from 'values'. If there is more than
// one string, it's an error, and exception will be thrown.
const std::string& s = po::validators::get_single_string(values);
// Do regex match and convert the interesting part to
// int.
boost::smatch match;
if (boost::regex_match(s, match, r)) {
#ifdef USE_NAMESPACE
v = boost::any(
ns1::magic_number(boost::lexical_cast<int>(match[1])));
#else
v = boost::any(
magic_number(boost::lexical_cast<int>(match[1])));
#endif
} else {
throw po::validation_error(po::validation_error::invalid_option_value);
}
}
int main(int ac, char* av[])
{
try {
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce a help screen")
("version,v", "print the version number")
#ifdef USE_NAMESPACE
("magic,m", po::
value<ns1::magic_number>(), "magic value (in NNN-NNN format)")
#else
("magic,m", po::
value<magic_number>(), "magic value (in NNN-NNN format)")
#endif
;
po::variables_map vm;
store(parse_command_line(ac, av, desc), vm);
if (vm.count("help")) {
std::cout << "Usage: regex [options]\n";
std::cout << desc;
return 0;
}
if (vm.count("version")) {
std::cout << "Version 1.\n";
return 0;
}
if (vm.count("magic")) {
#ifdef USE_NAMESPACE
std::cout << "The magic is \"" << vm["magic"].as<ns1::magic_number>().n << "\"\n";
#else
std::cout << "The magic is \"" << vm["magic"].as<magic_number>().n << "\"\n";
#endif
}
}
catch(std::exception& e)
{
std::cout << e.what() << "\n";
}
}
在 ns1
命名空间中定义 validate()
允许它编译(或将 magic_number
移出它,如您所见)。在 Boost 调用 validate()
.
的任何地方,名称查找似乎都不会考虑您的全局过载
编辑:我认为这是因为 boost::program_options
中定义的 validate()
的模板版本被认为比全局重载更匹配,但比在相同命名空间中定义的重载更差magic_number
。如果我对此有误,也许对 C++ 名称查找规则更了解的人可以发表评论。
如果 magic_number
不在命名空间中,以下改编示例将编译,但如果它在命名空间中,则会失败。
如果目标 class 在命名空间中,为什么找不到 validate
函数?
MSVC 上产生的错误是:
converter_lexical.hpp(243): error C2338: Target type is neither std::istream'able nor std::wistream'able.
我在使用 Clang here 时遇到了同样的错误。
进行测试; comment/uncomment #define USE_NAMESPACE
:
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// This example shows how a user-defined class can be parsed using
// specific mechanism -- not the iostream operations used by default.
//
// A new class 'magic_number' is defined and the 'validate' method is overloaded
// to validate the values of that class using Boost.Regex.
// To test, run
//
// regex -m 123-456
// regex -m 123-4567
//
// The first invocation should output:
//
// The magic is "456"
//
// and the second invocation should issue an error message.
#include <boost/program_options.hpp>
#include <boost/regex.hpp>
#include <iostream>
namespace po = boost::program_options;
//#define USE_NAMESPACE
#ifdef USE_NAMESPACE
namespace ns1{
#endif
/* Define a completely non-sensical class. */
struct magic_number {
public:
magic_number(int n) : n(n) {}
magic_number() = default;
int n;
};
#ifdef USE_NAMESPACE
}
#endif
/* Overload the 'validate' function for the user-defined class.
It makes sure that value is of form XXX-XXX
where X are digits and converts the second group to an integer.
This has no practical meaning, meant only to show how
regex can be used to validate values.
*/
#ifdef USE_NAMESPACE
void validate(boost::any& v, const std::vector<std::string>& values,
ns1::magic_number*, int)
#else
void validate(boost::any& v, const std::vector<std::string>& values,
magic_number*, int)
#endif
{
static boost::regex r("\d\d\d-(\d\d\d)");
// Make sure no previous assignment to 'a' was made.
po::validators::check_first_occurrence(v);
// Extract the first string from 'values'. If there is more than
// one string, it's an error, and exception will be thrown.
const std::string& s = po::validators::get_single_string(values);
// Do regex match and convert the interesting part to
// int.
boost::smatch match;
if (boost::regex_match(s, match, r)) {
#ifdef USE_NAMESPACE
v = boost::any(
ns1::magic_number(boost::lexical_cast<int>(match[1])));
#else
v = boost::any(
magic_number(boost::lexical_cast<int>(match[1])));
#endif
} else {
throw po::validation_error(po::validation_error::invalid_option_value);
}
}
int main(int ac, char* av[])
{
try {
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce a help screen")
("version,v", "print the version number")
#ifdef USE_NAMESPACE
("magic,m", po::
value<ns1::magic_number>(), "magic value (in NNN-NNN format)")
#else
("magic,m", po::
value<magic_number>(), "magic value (in NNN-NNN format)")
#endif
;
po::variables_map vm;
store(parse_command_line(ac, av, desc), vm);
if (vm.count("help")) {
std::cout << "Usage: regex [options]\n";
std::cout << desc;
return 0;
}
if (vm.count("version")) {
std::cout << "Version 1.\n";
return 0;
}
if (vm.count("magic")) {
#ifdef USE_NAMESPACE
std::cout << "The magic is \"" << vm["magic"].as<ns1::magic_number>().n << "\"\n";
#else
std::cout << "The magic is \"" << vm["magic"].as<magic_number>().n << "\"\n";
#endif
}
}
catch(std::exception& e)
{
std::cout << e.what() << "\n";
}
}
在 ns1
命名空间中定义 validate()
允许它编译(或将 magic_number
移出它,如您所见)。在 Boost 调用 validate()
.
编辑:我认为这是因为 boost::program_options
中定义的 validate()
的模板版本被认为比全局重载更匹配,但比在相同命名空间中定义的重载更差magic_number
。如果我对此有误,也许对 C++ 名称查找规则更了解的人可以发表评论。