【发布时间】:2020-03-14 09:24:44
【问题描述】:
显然,将 (almost) 任何内容添加到 std 命名空间是未定义行为。
我正在使用没有 std::chrono::parse()(仅限 C++20)的 C++14,但我需要从 istream 反序列化类型为 std::chrono::milliseconds(std::chrono::duration 的特化)的值。
虽然这可行,但我找不到任何允许它不是 UB 的例外:
namespace std {
std::istream& operator >>(std::istream & is, std::chrono::milliseconds & ms) {
std::string s;
is >> s;
ms = std::chrono::milliseconds(std::stoi(s));
return is;
}
}
由于这两种参数类型都不是 my 类型,我不确定如何在 std 命名空间之外安全地定义此运算符。
请注意,运算符将在 Boost::program_options 的深处调用,因此我认为我不能在自己的命名空间中定义运算符然后使用 using my_ns::operator>>,因为 using 声明的范围不会扩展到program_options 范围。
我是怎么来到这里的
作为Boost::program_options 的用户,我有一个特定的配置变量,我从存储为std::chrono::milliseconds 值的配置文件中读取:
std::chrono::milliseconds period;
po::options_description config_only_opts;
config_only_opts.add_options()
("control.period", po::value<std::chrono::milliseconds>(&period), "Specify the period in milliseconds");
// ...
auto istream = ifstream("config.cfg");
po::variables_map vm;
po::store(po::parse_config_file(istream, config_file_opts, false), vm);
根据Boost::program_options 文档,对于定义了operator >> (istream &, ...) 函数的类型,可以从配置文件中反序列化值。
如果没有上面提到的std的扩展,我最终会出现这种编译器错误:
/home/david/opt/boost-1.69/include/boost/lexical_cast/detail/converter_lexical.hpp: In instantiation of ‘struct boost::detail::deduce_target_char_impl<boost::detail::deduce_character_type_later<std::chrono::duration<long int, std::ratio<1, 1000> > > >’:
/home/david/opt/boost-1.69/include/boost/lexical_cast/detail/converter_lexical.hpp:270:89: required from ‘struct boost::detail::deduce_target_char<std::chrono::duration<long int, std::ratio<1, 1000> > >’
/home/david/opt/boost-1.69/include/boost/lexical_cast/detail/converter_lexical.hpp:407:92: required from ‘struct boost::detail::lexical_cast_stream_traits<std::__cxx11::basic_string<char>, std::chrono::duration<long int, std::ratio<1, 1000> > >’
/home/david/opt/boost-1.69/include/boost/lexical_cast/detail/converter_lexical.hpp:468:15: required from ‘struct boost::detail::lexical_converter_impl<std::chrono::duration<long int, std::ratio<1, 1000> >, std::__cxx11::basic_string<char> >’
/home/david/opt/boost-1.69/include/boost/lexical_cast/try_lexical_convert.hpp:201:44: required from ‘bool boost::conversion::detail::try_lexical_convert(const Source&, Target&) [with Target = std::chrono::duration<long int, std::ratio<1, 1000> >; Source = std::__cxx11::basic_string<char>]’
/home/david/opt/boost-1.69/include/boost/lexical_cast.hpp:41:60: required from ‘Target boost::lexical_cast(const Source&) [with Target = std::chrono::duration<long int, std::ratio<1, 1000> >; Source = std::__cxx11::basic_string<char>]’
/home/david/opt/boost-1.69/include/boost/program_options/detail/value_semantic.hpp:92:36: required from ‘void boost::program_options::validate(boost::any&, const std::vector<std::__cxx11::basic_string<charT> >&, T*, long int) [with T = std::chrono::duration<long int, std::ratio<1, 1000> >; charT = char]’
/home/david/opt/boost-1.69/include/boost/program_options/detail/value_semantic.hpp:184:21: required from ‘void boost::program_options::typed_value<T, charT>::xparse(boost::any&, const std::vector<std::__cxx11::basic_string<charT> >&) const [with T = std::chrono::duration<long int, std::ratio<1, 1000> >; charT = char]’
/home/david/myproj/Config.cpp:208:1: required from here
/home/david/opt/boost-1.69/include/boost/lexical_cast/detail/converter_lexical.hpp:243:13: error: static assertion failed: Target type is neither std::istream`able nor std::wistream`able
BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift<std::basic_istream<wchar_t>, T >::value),
^
【问题讨论】:
-
operator >>通常不需要位于std命名空间或任何其他命名空间中。如果您可以添加一些关于您如何在这个职位上结束的详细信息,我们也许可以让您摆脱它。 -
@user4581301 我已按要求添加了一些背景 - 谢谢。
-
我认为这个问题主要是因为我想将结果存储在
std::chrono::milliseconds中,而不是序列化格式的任何特殊之处。也许我应该通过纯整数提取值,然后在解析完成后使用它来初始化period值。
标签: c++ namespaces deserialization chrono boost-program-options