【问题标题】:template to_string << operator does not work for enum class模板 to_string << 运算符不适用于枚举类
【发布时间】:2021-03-02 20:57:33
【问题描述】:

我有一个包含 std::map 的类,我在下面对其进行了简化。我想实现一个 to_string() 函数,它将第一个和第二个映射条目通过运算符&lt;&lt; 流式传输到字符串流中 - 然后返回字符串结果。

这适用于 int、float、string 等...基本上可以流式传输的任何内容。

但是enum class xzy : int {...}; 不能是流式的——或者它必须首先是 static_cast。但是在我的模板中,如果我将 static_cast 放在 x.second 周围,那么它将破坏其他模板类型。

我想知道如何处理这个问题。我的第一个想法是尝试使用类型特征来检测类型是否是整数(然后对其进行静态转换),否则只依赖普通的operator &lt;&lt; 函数。

这里是类:

template<typename T1, typename T2>
class map_wrapper
{
public:
    std::map<T1, T2> m_map;
    std::map<T1, T2> &map() {return m_map;}
    std::string to_string()
    {
        std::stringstream ss;
        for (const auto &item : m_map)
        {
            // <----------------------- ISSUE HERE
            // So I want this to handle as many types as possible
            // Maybe I can do some sort of if type traits == integral then static cast?
            ss << item.first << ", " << static_cast<int>(item.second) << "\n";
            //ss << item.first << ", " << item.second << "\n";
        }
        return ss.str();
    }
};

这是我的测试代码:


enum class types : int
{
    type1,
    type2,
    type3
};

int main()
{
    // This is all ok
    map_wrapper<int, int> int_map;
    int_map.map() = {{1, 2}, {3, 4}};
    std::cout << int_map.to_string() << std::endl;

    // This only works if I static_cast the enum types to an int within to_string()
    map_wrapper<int, types> type_map;
    type_map.map() = {{1, types::type1}, {2, types::type2}};
    std::cout << type_map.to_string() << std::endl;
    return 0;
}

我已经注释了不能按我想要的那样工作的部分。

实时可编辑示例:https://godbolt.org/z/rh8Y5v

更新

注意类型枚举只是一个示例 - 我希望它可以理想地与任何枚举类一起使用

【问题讨论】:

    标签: c++ templates typetraits


    【解决方案1】:

    您不能专门化单个成员函数,您需要专门化整个类。如果你只需要这个函数,我建议提供一个模板运算符重载:

    template<typename Enum,
             typename = std::enable_if_t<std::is_enum_v<Enum>>>
    std::ostream& operator<< (std::ostream& out, Enum e)
    {
        return out << static_cast<int>(e);
    }
    

    See it online

    此运算符将接受任何enumenum class。如果你只想接受enum class,你可以使用 C++23 中的std::is_scoped_enum 或者推出你自己的(cppreference 中有一个可能的实现来提供帮助)。

    请注意,如果您想漂亮地打印特定的枚举,您仍然可以提供重载(如果我们这样做,则需要另一个完整的类专业化)。

    【讨论】:

    • 这个实时示例与我之前的代码相同,但添加了一个未使用的额外函数。如果我删除了 to_string() 中的 static_cast 它仍然无法编译......所以我不确定你的解决方案是什么 - 我错过了什么? (参见:godbolt.org/z/Mb5dE4is_scoped_enum 特征看起来很有趣 - 但 AFAIK 这是一个 c++23 功能,所以我还没有使用它:(
    • 好的,我认为您的代码中只有一个 typeo:这似乎可以工作:godbolt.org/z/Pnzveq
    • 啊,是的,我的错。这就解释了为什么它用错字编译。 std::is_enum 可以用来代替 std::is_scoped_enum - 显式转换不会受到伤害。我一会儿再更新。
    • 是的,我只是想到了这一点并尝试了:typename = std::enable_if_t&lt;std::is_enum_v&lt;Enum&gt;&gt;&gt; 与您的模板功能 - 效果很好,谢谢! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 2011-01-28
    • 1970-01-01
    相关资源
    最近更新 更多