c++ - 在命名空间中对自己的类使用 boost::program_options::validate

标签 c++ boost boost-program-options

如果 magic_number 不在命名空间中,则下面的改编示例会编译,但如果它在命名空间中,则会失败。

如果目标类在命名空间中,为什么找不到 validate 函数?


在 MSVC 上产生的错误是:

converter_lexical.hpp(243): error C2338: Target type is neither std::istream'able nor std::wistream'able.

我在使用 Clang here 时遇到了同样的错误。


测试;注释/取消注释 #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++ 名称查找规则更了解的人可以发表评论。

关于c++ - 在命名空间中对自己的类使用 boost::program_options::validate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51801770/

相关文章:

c++ - 如何为 std::array 中的 std::vectors 保留内存?

c++ - 创建未初始化的 SSE 值

c++ - 将 vector 推回不同的位置

c++ - 如何使用模板和继承来更正和改进此 C++ 代码?

boost - const shared_ptr到shared_ptr

c++ - 从返回 Boost 可选的函数返回右值引用

c++ - 正则表达式搜索匹配不使用组

c++ - 跳过未知选项而不抛出 boost 程序选项

c++ - 使用 boost::{program_options,property_tree} 读取/写入 inifiles

c++ - 在Boost program_options中的配置文件中处理无值选项