【问题标题】:How to check if a variable can be written into a stream如何检查变量是否可以写入流
【发布时间】:2021-12-28 02:22:35
【问题描述】:

我正在用 C++14 开发一个工具类,它允许开发人员轻松打印各种对象。

对于std::map对象,我尝试开发这样一个功能:

template<typename M, typename = std::enable_if_t<
                                std::is_same<M, std::map<typename M::key_type, typename M::mapped_type>>::value ||
                                std::is_same<M, std::unordered_map<typename M::key_type, typename M::mapped_type>>::value>>
std::string map2String(const M& mp) {
    std::stringstream res;
    for (const auto& element : mp) {
        res << element.first << "," << element.second << "|";
    }
    return res.str();
}

它按预期工作。 (顺便说一句,C++11也可以,我可以用C++11的方式替换std::enable_if_t。)

但是,如您所见,std::stringstream 已被使用,这意味着必须对M::key_typeM::mapped_type 进行流式传输。

但我不知道如何检查它们是否是流式传输的。我需要这样的东西:

std::enable_if_t<is_streamable<typename M::key_type>>::value

但是标准库中没有is_streamable。如果没有is_streamable,是否有任何其他方法可以为那些在调用我的函数时无法写入流的类型产生编译时错误?

【问题讨论】:

    标签: c++ templates c++14 stringstream enable-if


    【解决方案1】:

    这是在 C++14 中创建自己的类型特征的简单方法:

    #include <type_traits>
    #include <utility>
    
    namespace is_streamable_impl {
        template <typename T, typename Enable = void>
        struct check : public std::false_type {};
    
        template <typename T>
        struct check<T,
            std::enable_if_t<std::is_same<
                decltype(std::declval<std::ostream&>() << std::declval<T>()),
                std::ostream&>::value>>
        : public std::true_type {};
    }
    
    template <typename T>
    struct is_streamable : public std::integral_constant<bool, check<T>::value> {};
    

    该特征检查os &lt;&lt; valstd::ostream 类型的有效左值表达式,给定一个std::ostream 类型的左值表达式os 和一个表达式val,其类型和值类别与T 相关。也可以编写关于确切要求的其他变体。

    上面is_streamable_impl::check 的定义实际上可能直接作为特征就足够了。但它确实允许有人将其误用为check&lt;bad_type, void&gt;::value == true。您可以将其称为不好的用法,而不必担心;或者这里的这个模式确保额外的模板参数被隐藏起来。

    对于您的示例使用,我实际上会检查is_streamable&lt;const typename M::key_type&amp;&gt;。这可能会产生与直接key_type 相同的结果,但对于可能很重要的奇怪情况,它会更精确。

    【讨论】:

      【解决方案2】:

      您可以使用std::ostream 来检查它们是否可以用作operator&lt;&lt; 的操作数。

      template<typename M, typename = std::enable_if_t<
                                      std::is_same<M, std::map<typename M::key_type, typename M::mapped_type>>::value ||
                                      std::is_same<M, std::unordered_map<typename M::key_type, typename M::mapped_type>>::value>,
                           typename = decltype(std::declval<std::ostream>() << std::declval<typename M::key_type>()),
                           typename = decltype(std::declval<std::ostream>() << std::declval<typename M::mapped_type>())>
      std::string map2String(const M& mp) {
          ...
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-03
        • 2015-03-16
        • 2017-09-21
        • 2016-01-13
        相关资源
        最近更新 更多