首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在C++中将数据结构表示为字符串的首选方法是什么?

在C++中将数据结构表示为字符串的首选方法是什么?
EN

Stack Overflow用户
提问于 2019-06-05 05:58:56
回答 1查看 83关注 0票数 0

在C++中表示数据结构的首选方法是什么?我想使用字符串,但如果有更好的选择,我也愿意尝试一下。

我一直在为一个更大的程序创建一个数据结构。该结构应该表示类似于Python字典的东西。我想将整个数据结构打印为一个字符串。在C++中有这样做的标准方法吗?指南建议使用to_string()函数,但是我不确定它是否如我所想的那样工作。

我正在使用模板类,我不确定是否有一次性的解决方案来处理抛给程序的键/值的任何组合。

到目前为止,我一直在用char's进行测试。

代码语言:javascript
复制
// Table class
std::string toString()
  {
    std::string result = " { ";
    ListNode<Key, Value>* current = this->table;
    while(current != nullptr)
    {
      result += current->toString();
      current = current->next;
    }
    result += " } ";
    return result;
  }

// List Class
std::string toString()
  {
    std::string result = "";
    result += std::to_string(this->key);
    result += " : ";

    Node<Value>* current = this->list;

    while(current != nullptr) // changed to be current, not list
    {
      result += std::to_string(current->value);
      current = current->next;
    }

    return result; // added return
  }

此函数的工作方式更像是特定字符串的构建器。它进入到较小的数据结构中,调用类似的函数来到达基础。

我希望有这样的东西:

{ Key1 : value1,value2,value3,Key2: value1,Key3: value1,value2 }

我刚收到了{}

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-05 09:03:34

强化Everything

我认为这对您来说是很好的,看看它是如何在实践中工作的示例。字符串化应该是快速、简单和简单的。不幸的是,它没有内置到标准库中。

然而,在100多行代码中,我们可以编写代码来字符串化std::mapstd::tuplestd::unordered_mapstd::setstd::unordered_setstd::liststd::vector、D11、D12、E113以及它们的任意组合。例如,您可以有一个包含in和字符串之间的unordered_maps向量的元组。材料:

代码语言:javascript
复制
std::vector<std::unordered_map<int, std::string>> vect {
    {{10, "Hello"}, {20, "World"}},
    {{1, "1"}, {2, "2"}, {3, "3"}},
    {{1000, "thousand"}, {1000000, "million"}},
};

// If we can print this, we're GOLDEN
auto justTryAndPrintMe = std::tuple{10, 20, vect, 0.3f, short(3), 2398987239890ll}; 

由于它的设计,我们编写的接口将很容易扩展到自定义类型。

描述接口

该界面分为三个部分。

  • to_string重载(这是由std::to_string)
  • append_to重载提供的(我们编写这些)
  • One stringify函数模板,它调用append_to

让我们先来看看stringify函数:

代码语言:javascript
复制
namespace txt 
{
    template<class T>
    std::string stringify(T const& t) 
    {
        std::string s;
        append_to(s, t); 
        return s; 
    }
}

为什么使用append_to?附加到字符串的速度非常快。当您多次追加时,std::string保留了比实际需要更多的容量,因此任何一次追加都不太可能导致新的分配,因为字符串将具有足够的容量来容纳对象。这减少了对newdelete的调用。

编写接口。

append_to有一个后备功能,它使用to_string,以及许多针对不同容器的专门化。专门化将是向前声明的,因此它们彼此可见。

后退。

这个版本是专门化程度最低的,只有在没有其他方法附加对象时才会启用。我们使用SFINAE来检查to_string方法的存在。

这个方法可以来自命名空间std;它可以在全局命名空间中定义,甚至可以在与用户定义类型相同的命名空间中定义to_string to_string。在最后一种情况下,编译器通过ADL (参数相关查找)找到它。

代码语言:javascript
复制
namespace txt {
    using std::to_string;

    // This nasty bit in the template declaration is the SFINAE
    template<class T, class = decltype(to_string(std::declval<T>()))>
    void append_to(std::string& s, T const& obj)
    {
        s += to_string(obj); 
    }
}

特殊情况

对于std::string或cstring,有to to_string函数,但是为它们编写高效的追加函数很简单。

代码语言:javascript
复制
// namespace txt

template<size_t N>
void append_to(std::string& s, char const(&str)[N]) {
    s.append(str, N - 1); 
}
void append_to(std::string& s, std::string const& s2) {
    s += s2; 
}

STL容器和类型的正向声明

向前声明它们是一个好主意,因为这样做将允许它们相互调用。

代码语言:javascript
复制
// namespace txt

template<class... T>
void append_to(std::string& s, std::tuple<T...> const& t); 
template<class F, class S>
void append_to(std::string& s, std::pair<F, S> const& p); 
template<class T>
void append_to(std::string& s, std::vector<T> const& v); 
template<class T>
void append_to(std::string& s, std::set<T> const& v); 
template<class T>
void append_to(std::string& s, std::list<T> const& v); 
template<class Key, class Value>
void append_to(std::string& s, std::map<Key, Value> const& v); 
template<class T>
void append_to(std::string& s, std::unordered_set<T> const& v); 
template<class Key, class Value>
void append_to(std::string& s, std::unordered_map<Key, Value> const& v); 

装卸范围

这是非常简单的。我们将编写一个接受begin和end迭代器以及well use theappend_rangefunction to implementappend_to`作为append_range容器的STL函数。

代码语言:javascript
复制
// namespace txt

template<class It>
void append_range(std::string& s, It begin, It end) {
    if(begin == end) {
        s += "{}"; 
    } else {
        s += '{';
        append_to(s, *begin); 
        ++begin;
        for(; begin != end; ++begin) {
            s += ", "; 
            append_to(s, *begin); 
        }
        s += '}'; 
    }
}

处理对和元组

我们可以使用std::apply (在C++17中引入)将元组扩展为参数包。一旦我们有了它,我们就可以使用一个折叠表达式来附加每个元素。

代码语言:javascript
复制
// namespace txt

template<class... T>
void append_to(std::string& s, std::tuple<T...> const& t) 
{
    if constexpr(sizeof...(T) == 0) 
    {
        s += "{}"; 
    } 
    else 
    {
        // This is a lambda. We'll use it to append the tuple elements. 
        auto append_inputs = [&s](auto& first, auto&... rest) 
        {
            // Append the first one
            append_to(s, first); 
            // Append the rest, separated by commas
            ((s += ", ", append_to(s, rest)) , ...); 
        }; 

        s += '('; 
        std::apply(append_inputs, t); 
        s += ')'; 
    }
}

添加一个对也是非常简单的:

代码语言:javascript
复制
// namespace txt

template<class F, class S>
void append_to(std::string& s, std::pair<F, S> const& p) 
{
    s += '(';
    append_to(s, p.first); 
    s += ", "; 
    append_to(s, p.second); 
    s += ')'; 
}

处理STL容器

对于所有这些,我们只在开始和结束迭代器上调用append_range

代码语言:javascript
复制
template<class T>
void append_to(std::string& s, std::vector<T> const& v) {
    append_range(s, v.data(), v.data() + v.size()); 
}
template<class T>
void append_to(std::string& s, std::set<T> const& v) {
    append_range(s, v.begin(), v.end()); 
}
template<class Key, class Value>
void append_to(std::string& s, std::map<Key, Value> const& v) {
    append_range(s, v.begin(), v.end()); 
}
template<class T>
void append_to(std::string& s, std::unordered_set<T> const& v) {
    append_range(s, v.begin(), v.end()); 
}
template<class Key, class Value>
void append_to(std::string& s, std::unordered_map<Key, Value> const& v) {
    append_range(s, v.begin(), v.end()); 
}

自定义类型:就像编写函数一样简单

这真的很简单。我们可以只为该类型编写一个append_to方法。它可以在您包含包含namespace txt的头文件之后执行。ADL会自动找到它。

代码语言:javascript
复制
namespace foo {
    struct MyVec {
        int x;
        int y;
        int z;
    }; 
    void append_to(std::string& s, MyVec v) {
        using txt::append_to; 

        s += '<'; 
        append_to(s, v.x);
        s += ", "; 
        append_to(s, v.y);
        s += ", ";  
        append_to(s, v.z); 
        s += '>'; 
    }
}

Click here to run the code

在您的库中使用此代码

我们可以很容易地为Table编写一个append_to函数!

代码语言:javascript
复制
namespace YourNamespace {
// Here, I forward declare append_to for table 
// Forward-declaring it allows you to have tables of tables
template <class Key, class Value>
void append_to(std::string& s, Table<Key, Value> const& table); 

template <class Key, class Value>
void append_to(std::string& s, ListNode<Key, Value> const& node) 
{
    // We need to use the txt version so it's included in our overload set
    using txt::append_to; 

    append_to(s, node.key); 
    s += " : "; 
    append_to(s, node.value);  
}

template <class Key, class Value>
void append_to(std::string& s, Table<Key, Value> const& table) 
{
    using txt::append_to; 

    ListNode<Key, Value> const* current = table.table;
    if (current == nullptr) 
    {
        s += "{}";
    } 
    else 
    {
        s += "{ ";
        append_to(s, *current);
        current = current->next;
        for (; current != nullptr; current = current->next) {
            s += ", ";
            append_to(s, *current);
        }
        s += " }";
    }
}
} // namespace YourNamespace
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56451865

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档