c++ - 如何在不扩展命名空间 `std` 的情况下为缺少预定义运算符的标准类型定义运算符 >> (istream &, ...)?

标签 c++ namespaces deserialization c++-chrono boost-program-options

显然,向 std 添加( almost )任何内容是未定义的行为命名空间。

我正在使用没有 std::chrono::parse() 的 C++14 (仅限 C++20)但我需要反序列化 std::chrono::milliseconds 类型的值(std::chrono::duration 的特化)来自 istream .

虽然这可行,但我找不到任何允许这不是 UB 的异常(exception)情况:

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;
}
}

因为这两个参数类型都不是我的类型,所以我不确定如何在 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),
             ^

最佳答案

即使标准允许运算符重载,我也不建议添加该函数。这不是从 std::istream 读取 std::chrono::milliseconds 的通用方法。您所拥有的是您的应用程序自己从 std::istream 中读取此类对象的方式。

我建议在您的应用程序自己的命名空间中添加一个函数。

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;
   }
}

关于c++ - 如何在不扩展命名空间 `std` 的情况下为缺少预定义运算符的标准类型定义运算符 >> (istream &, ...)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58924211/

相关文章:

c# - 反序列化 :anyType 的列表

c++ - 指针上的算术是关联的吗?

ruby-on-rails-3 - 导轨缓存 : expire_action in another namespace

php - 如何使用不同的文件名自动加载类? PHP

java - Jackson 自定义序列化以展平对象

c# - 可以将 JSON 字符串反序列化为 C# 数组吗?

c++ - 使用 C++ GUI 应用程序检查网络状态的 QT

c++ - 如何使随机损失位服从高斯分布

c++ - 创建动态pthread_t时出错

java - 解码不属于命名空间的 xml 元素