首页 > 解决方案 > 为什么要在命名空间 break boost program_options 中定义 operator<< 和 >>?

问题描述

这里开始,如果我将重载的运算符放在命名空间中,它应该可以工作。但是我发现它实际上不起作用,编译器总是抱怨它找不到<<或>>。

在以下示例中,如果我打开 USE_NAMESPACE,编译将失败。但是 >> 和 << 实际上在 program_options 之外工作。如果我关闭 ENABLE_PO 它工作正常。

这里会发生什么?我该如何解决?

#include <iostream>
#include <sstream>
#include <string>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
#define ENABLE_PO 1
#define USE_NAMESPACE 0
enum class test_enum_t {bar, foo};
#if USE_NAMESPACE
namespace test_enum
{
#endif

    template<typename istream_T>
    istream_T& operator>>(istream_T& in, test_enum_t& value)
    {
        std::string in_str;
        in >> in_str;
        if (in_str == "bar")
            value = test_enum_t::bar;
        else if(in_str == "foo")
            value = test_enum_t::foo;
        else
            in.setstate(std::ios_base::failbit);
        return in;
    }

    template<typename ostream_T>
    ostream_T &operator<<(ostream_T &out, const test_enum_t& value) {
        if (value == test_enum_t::bar)
            out << "bar";
        else if (value == test_enum_t::foo)
            out << "foo";
        else
            out << "unknown-value";
        return out;
    }

#if USE_NAMESPACE
}
using namespace test_enum;
#endif

#if ENABLE_PO
int simple_options(int argc, char *argv[])
{
    test_enum_t test = test_enum_t::bar;
    po::options_description config("Configuration");
    config.add_options()
        ("help", "produce help message")
        ("in,i", po::value(&test)->default_value(test), "test enum class as input.")
        ;
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, config),vm);
    po::notify(vm);
    if (vm.count("help")) {
        std::cout << config << "\n";
        return 1;
    }

    return 0;
}
#endif
int main(int argc, char *argv[])
{
#if ENABLE_PO
    simple_options(argc, argv);
#endif
    test_enum_t test;
    std::cout << "input bar or foo" << std::endl;
    std::cin >> test;
    if (std::cin.fail())
    {
        std::cerr << "not a valid value";
        exit(1);
    }
    std::cout << test << std::endl;
    return 0;
}

标签: c++boost

解决方案


如前所述,您需要 ADL(Argument Dependent Lookup)才能成功。

如果您可以控制 POI(实例化点),您也可以主动use使用专用命名空间中的名称。在这种情况下,您需要在实例化解析代码的点之前use定义的 TU 中的这些名称simple_options,例如您定义选项描述组件的位置。

这是演示它的代码的简化版本

住在科利鲁

#include <boost/program_options.hpp>
#include <iostream>
#include <sstream>
#include <string>
enum class test_enum_t { bar, foo };

namespace test_enum {

    template <typename istream_T>
        istream_T& operator>>(istream_T& in, test_enum_t& value) {
            std::string in_str;
            in >> in_str;
            if (in_str == "bar")
                value = test_enum_t::bar;
            else if (in_str == "foo")
                value = test_enum_t::foo;
            else
                in.setstate(std::ios_base::failbit);
            return in;
        }

    template <typename ostream_T>
        ostream_T& operator<<(ostream_T& out, const test_enum_t& value) {
            if (value == test_enum_t::bar)
                out << "bar";
            else if (value == test_enum_t::foo)
                out << "foo";
            else
                out << "unknown-value";
            return out;
        }

}

using test_enum::operator<<;
using test_enum::operator>>;

test_enum_t simple_options(int argc, char* argv[]) {
    namespace po = boost::program_options;

    test_enum_t test = test_enum_t::bar;
    po::options_description config("Configuration");

    config.add_options()("help", "produce help message")(
            "in,i", po::value(&test)->default_value(test),
            "test enum class as input.");

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, config), vm);
    po::notify(vm);
    if (vm.count("help")) {
        std::cout << config << "\n";
        exit(1);
    }
    return test;
}

int main(int argc, char* argv[]) {
    std::cout << "Command line input: " << simple_options(argc, argv) << "\n";

    std::cout << "input bar or foo" << std::endl;
    if (test_enum_t test; std::cin >> test) {
        std::cout << test << std::endl;
    } else {
        std::cerr << "not a valid value";
        return 1;
    }
}

印刷

g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp -lboost_program_options
./a.out -i bar <<<foo
Command line input: bar
input bar or foo
foo

推荐阅读