[英]How do I define operator >> (istream &, …) for a standard type that lacks a pre-defined operator without extending namespace `std`?
Apparently it's Undefined Behaviour to add ( almost ) anything to the std
namespace.显然,将(几乎)任何东西添加到
std
命名空间是未定义的行为。
I'm using C++14 which has no std::chrono::parse()
(C++20 only) but I need to deserialise values of type std::chrono::milliseconds
(a specialisation of std::chrono::duration
) from an istream
.我正在使用 C++14 ,它没有
std::chrono::parse()
(仅限 C++20),但我需要反序列化std::chrono::milliseconds
类型的值( std::chrono::duration
的特化) 来自istream
。
Although this works, I can't find any exceptions that allow this to not be UB:虽然这可行,但我找不到任何允许它不是 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;
}
}
Since neither of these two parameter types are my types, I'm not sure how I'd safely define this operator outside of the std
namespace.由于这两种参数类型都不是我的类型,我不确定如何在
std
命名空间之外安全地定义此运算符。
Note that the operator will be called deep within Boost::program_options
so I don't think I can define the operator in my own namespace and then use using my_ns::operator>>
because the scope of that using
declaration won't extend into the program_options
scope.请注意,运算符将在
Boost::program_options
的深处调用,因此我认为我不能在自己的命名空间中定义运算符然后使用using my_ns::operator>>
因为该using
声明的 scope 不会扩展到程序选项program_options
。
As a user of Boost::program_options
I have a particular configuration variable that I read from a configuration file that is stored as a std::chrono::milliseconds
value:作为
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);
According to the Boost::program_options
documentation, it is possible to deserialise values from the config file for types that have an operator >> (istream &, ...)
function defined.根据
Boost::program_options
文档,对于定义了operator >> (istream &, ...)
function 的类型,可以从配置文件中反序列化值。
Without the extention to std
mentioned above, I end up with this kind of compiler error:如果没有上面提到的对
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),
^
I would not recommend adding that function even if the standard allowed the operator to be overloaded.即使标准允许运算符重载,我也不建议添加 function。 It's not a generic way to read a
std::chrono::milliseconds
from a std::istream
.这不是从
std::istream
读取std::chrono::milliseconds
的通用方法。 What you have is your application's own way of reading such an object from a std::istream
.您所拥有的是您的应用程序自己从
std::istream
读取此类 object 的方式。
I recommend adding a function in your application's own namespace
.我建议在应用程序自己的
namespace
中添加 function 。
namespace MyApp
{
std::istream& readChronoMilliSeconds(std::istream& is, std::chrono::milliseconds & ms)
{
std::string s;
is >> s;
ms = std::chrono::milliseconds(std::stoi(s));
return is;
}
}
Using fancy types for input parameter is fooling yourself because input parameters generally are nothing else than numbers, strings or lists of them.对输入参数使用花哨的类型是在自欺欺人,因为输入参数通常只是数字、字符串或它们的列表。
What I recommend is to take a proper integer value and convert internally to milliseconds.我建议采用适当的 integer 值并在内部转换为毫秒。
int period_in_ms = 0;
...
config_only_opts.add_options()
("control.period_in_ms", po::value<int>(&period_in_ms), "Specify the period in milliseconds");
...
auto period = std::chrono::milliseconds(period_in_ms);
You can use the "notify" mechanism in Boost.ProgramOptions to update the value of period
in-place but it is not worth the trouble.您可以使用 Boost.ProgramOptions 中的“通知”机制来就地更新
period
的值,但这不值得麻烦。
If you want to input the parameter in a certain format (eg finish with "ms", as in "100ms") then take a value<std::string>
and make the conversion/parsing.如果您想以某种格式输入参数(例如以“ms”结尾,如“100ms”),则取一个
value<std::string>
并进行转换/解析。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.