【C++】枚举转字符串

文章介绍了如何利用Boost库中的BOOST_DESCRIBE_ENUM和mp_for_each函数将枚举和基本类型转换为字符串,提供了一系列模板函数,包括处理容器和自定义结构体的ToString方法。
摘要由CSDN通过智能技术生成

背景

业务中涉及枚举的打印,一般采用%d的方式打印输出,此方式打印效果不直观,需要一种将枚举转为字符串类型的打印方法。本文提出的解决思路不一定适合所有的场景,请各位小伙伴自行斟酌。

实现思路

利用boost库中的BOOST_DESCRIBE_ENUMmp_for_each配合,可实现枚举的打印,官方提供的示例代码如下:
boost库中给的示例代码
此种枚举转字符串的方式有个限制,若是枚举项超出52个,则无法使用BOOST_DESCRIBE_ENUM,这个受限于boost的实现。

基于上面的这种方式可以实现枚举转字符串,在利用%s打印输出的时候,为了提升使用的便捷性,可以定义TOCHAR宏,如下:

#define TOCHAR(e) ToString(e)

// 使用示例
enum class Color {
	RED = 0,
	YELLOW = 1,
	GREEN = 2
}
LOG("Current color is %s", TOCHAR(Color::Red)); // 输出:Current color is RED(1)

扩展

基于上面的实现,可以尝试将所有的类型都纳入到ToString函数中,实现对所有类型转string。

#define TOCHAR(T) ToString(T)

// 枚举类型转换为字符串的模板函数
template <typename E>
inline typename std::enable_if<std::is_enum<E>::value, std::string>::type ToString(const E& enumerator)
{
    std::string result = "[UNDEFINED]";
    boost::mp11::mp_for_each< boost::describe::describe_enumerators<E> >([&](auto description){
        if (enumerator == description.value) {
            result = description.name;
        }
    });
    return result + std::string("(") + std::to_string(static_cast<int>(enumerator)) + std::string(")");
}

// 基本类型转换为字符串的模板函数
template <typename T>
inline typename std::enable_if<!std::is_enum<T>::value, std::string>::type ToString(T value)
{
    return boost::lexical_cast<std::string>(value);
}

// boolean转换为字符串的模板函数
inline std::string ToString(bool boolean)
{
    return boolean ? "true" : "false";
}

// vector转换为字符串的模板函数
template <typename T>
inline std::string ToString(const std::vector<T>& vec)
{
    std::stringstream ss;
    ss << "[";
    if (!vec.empty())
    {
        // 输出第一个元素
        ss << ToString(vec[0]);
        // 输出剩余元素
        for (size_t i = 1; i < vec.size(); ++i)
        {
            ss << ", " << ToString(vec[i]);
        }
    }
    ss << "]";
    return ss.str();
}

// set转换为字符串的模板函数
template<typename T>
inline std::string ToString(const std::set<T>& container) {
    std::ostringstream oss;
    oss << "[";
    for (const auto& element : container) {
        oss << ToString(element) << ", ";
    }
    std::string result = oss.str();
    if (!result.empty()) {
        result.pop_back(); // 移除最后一个逗号
        result.pop_back(); // 移除空格
    }
    result += "]";
    return result;
}

// map转换为字符串的模板函数
template<typename KeyType, typename ValueType>
inline std::string ToString(const std::map<KeyType, ValueType>& inputMap) {
    std::ostringstream oss;
    oss << "{";
    for (const auto& pair : inputMap) {
        oss << "{"<< ToString(pair.first) << ": " << ToString(pair.second) << "}, ";
    }
    std::string result = oss.str();
    if (!result.empty()) {
        result.pop_back(); // 移除最后一个逗号
        result.pop_back(); // 移除空格
    }
    result += "}}";
    return result;
}

// unordered_map转换为字符串的模板函数
template<typename KeyType, typename ValueType>
inline std::string ToString(const std::unordered_map<KeyType, ValueType>& inputMap) {
    std::ostringstream oss;
    oss << "{";
    for (const auto& pair : inputMap) {
        oss << "{"<< ToString(pair.first) << ": " << ToString(pair.second) << "}, ";
    }
    std::string result = oss.str();
    if (!result.empty()) {
        result.pop_back(); // 移除最后一个逗号
        result.pop_back(); // 移除空格
    }
    result += "}}";
    return result;
}

测试用例

TEST_F(TestBoost, ToString_for_basic_type)
{
    Value e = Value::Value2;
    int intVar = 123;
    short shortVar = 456;
    long longVar = 789;
    long long longLongVar = 1234567890;
    char charVar = 'A';
    unsigned int unsignedIntVar = 234;
    float floatVar = 3.14f;
    double doubleVar = 2.71828;
    long double longDoubleVar = 1.618033988749895;
    bool boolVar = true;

    EXPECT_EQ(ToString(e), "Value2(2)");
    EXPECT_EQ(ToString(intVar), "123");
    EXPECT_EQ(ToString(shortVar), "456");
    EXPECT_EQ(ToString(longVar), "789");
    EXPECT_EQ(ToString(longLongVar), "1234567890");
    EXPECT_EQ(ToString(charVar), "A");
    EXPECT_EQ(ToString(unsignedIntVar), "234");
    EXPECT_EQ(ToString(floatVar), "3.1400001");
    EXPECT_EQ(ToString(doubleVar), "2.71828");
    EXPECT_EQ(ToString(longDoubleVar), "1.6180339887498949");
    EXPECT_EQ(ToString(boolVar), "true");
}

TEST_F(TestBoost, ToString_for_container_type)
{
    std::vector<std::string> stringVector = {"x", "y", "z"};
    std::set<double> doubleSet = {1.1, 2.2, 3.3, 4.4, 5.5};
    std::map<std::string, int> doubleMap {{"apple", 5.1}, {"banana", 3.2}, {"orange", 8.3}};
    std::unordered_map<std::string, int> doubleUnorderedMap {{"apple", 5.1}, {"banana", 3.2}, {"orange", 8.3}};
    std::unordered_map<std::string, std::vector<int>> nestedUnorderedMap {{"a", {1, 2}}, {"b", {3}}, {"c", {4, 5, 6}}};

    EXPECT_EQ(ToString(stringVector), "[x, y, z]");
    EXPECT_EQ(ToString(doubleSet), "[1.1000000000000001, 2.2000000000000002, 3.2999999999999998, 4.4000000000000004, 5.5]");
    EXPECT_EQ(ToString(doubleMap), "{{apple: 5}, {banana: 3}, {orange: 8}}}");
    EXPECT_EQ(ToString(doubleUnorderedMap), "{{orange: 8}, {banana: 3}, {apple: 5}}}");
    EXPECT_EQ(ToString(nestedUnorderedMap), "{{c: [4, 5, 6]}, {b: [3]}, {a: [1, 2]}}}");
}

若是需要对自定义的结构体也纳入TOCHAR需要定义一套该结构体的ToString方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值