首页 > 解决方案 > C++ 中通用容器的字符串化函数

问题描述

如何为通用容器也为嵌套容器创建通用字符串化函数,例如map<string,vector<list<int>>>?这是我的尝试,但它不起作用。

template<class T>
string stringify(const T& c) {
    int length = c.size();
    string str = "[";
    int i=0;
    for (; i <= length-2; i++) {
        str += stringfy(c[i]) + ", ";
    }
    str += c[i] + "]";
    return str;
}

标签: c++stringtemplates

解决方案


这是可行的,但大多毫无意义,因为您通常会知道必须处理什么样的数据。

我设法想出了这样的事情。它适用于可通过 for-each 循环或元组迭代或已重载的每种类型operator<<。你可以在没有 C++20 特性的情况下做到这一点,但这将是一个完全 SFINAE 的混乱。

#include <iostream>
#include <string>
#include <type_traits>
#include <map>
#include <list>
#include <vector>
#include <tuple>
#include <sstream>

using namespace std;

template <typename T>
concept InterableRange = requires (T a) {
    std::begin(a);
    std::end(a);
};

template <typename T>
concept TupleLikeType = requires (T a) {
    std::tuple_size<T>();
};

template<TupleLikeType T>
string stringify(const T& c);

template<class T>
string stringify(const T& c);

template<InterableRange T>
string stringify(const T& c) {
    string str = "[ ";
    auto size = std::size(c);
    std::size_t i = 0;
    for (const auto& elem : c) {
        str += stringify(elem);
        if(i++ < size - 1)
            str += ", ";
    }
    str += " ]";
    return str;
}

template<TupleLikeType T>
string stringify(const T& c) {
    string str = "[ ";
    auto size = std::tuple_size<T>();
    std::size_t i = 0;

    std::stringstream input;   
    auto insert = [&input, size, &i](const auto& data) {
        input << stringify(data);
        if(i++ < size - 1)
        {
            input.put(',');
            input.put(' ');
        }
    };
    std::apply([&insert](const auto&... args){
        (insert(args), ...);
    }, c);

    str += input.str();
    str += " ]";
    return str;
}

template<class T>
string stringify(const T& c) {
    std::stringstream input;   
    input << c;
    return input.str();
}


int main() {
    map<string,vector<list<int>>> m {
        { "1", {{1,2}, {3, 4}}},
        { "2", {{10,20}, {30, 40}}}
    };
    cout << stringify(m);
}

它会打印

[ [ [ 1 ], [ [ 1, 2 ], [ 3, 4 ] ] ], [ [ 2 ], [ [ 10, 20 ], [ 30, 40 ] ] ] ]

推荐阅读