c++ - 为什么要在命名空间 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;
}
解决方案
如前所述,您需要 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
推荐阅读
- go - 如何根据特定时区间隔运行 cron 作业
- java - 使用递归查找字符串中最长的回文
- javascript - 模态图像 - 使用目录图像 - W3 Schools Modal Image mod
- lambda - 如何在 kotlin 中序列化 lambda
- c++ - 隐式模板实例化编译时差
- javascript - 使用 javascript 或其他语言实现 Android 主屏幕小部件
- javascript - 用 0 替换前三个字符
- sql-server - SQL Server:无法添加约束
- wordpress - 在 woocommerce 付款中启用付款选项后未显示付款选项。
- azure-storage - 通过 azure powershell (arm) 创建 vm 的快照