模板 to_string << 运算符不适用于枚举 class

template to_string << operator does not work for enum class

我有一个 class 包裹了一个 std::map,我在下面对其进行了简化。我想实现一个 to_string() 函数,该函数使用运算符 << 将第一个和第二个映射条目流式传输到字符串流中 - 然后 returns 字符串结果。

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

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

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

这里是 class:

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

更新

请注意枚举类型只是一个示例 - 我希望它能与任何枚举一起工作 class 理想情况下

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

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 中有一个可能的实现可以提供帮助)。

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