在C++中表示数据结构的首选方法是什么?我想使用字符串,但如果有更好的选择,我也愿意尝试一下。
我一直在为一个更大的程序创建一个数据结构。该结构应该表示类似于Python字典的东西。我想将整个数据结构打印为一个字符串。在C++中有这样做的标准方法吗?指南建议使用to_string()
函数,但是我不确定它是否如我所想的那样工作。
我正在使用模板类,我不确定是否有一次性的解决方案来处理抛给程序的键/值的任何组合。
到目前为止,我一直在用char
's进行测试。
// 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 }
我刚收到了{}
发布于 2019-06-05 09:03:34
强化Everything
我认为这对您来说是很好的,看看它是如何在实践中工作的示例。字符串化应该是快速、简单和简单的。不幸的是,它没有内置到标准库中。
然而,在100多行代码中,我们可以编写代码来字符串化std::map
、std::tuple
、std::unordered_map
、std::set
、std::unordered_set
、std::list
、std::vector
、D11、D12、E113以及它们的任意组合。例如,您可以有一个包含in和字符串之间的unordered_maps向量的元组。材料:
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
重载提供的(我们编写这些)stringify
函数模板,它调用append_to
。让我们先来看看stringify
函数:
namespace txt
{
template<class T>
std::string stringify(T const& t)
{
std::string s;
append_to(s, t);
return s;
}
}
为什么使用
append_to
?附加到字符串的速度非常快。当您多次追加时,std::string
保留了比实际需要更多的容量,因此任何一次追加都不太可能导致新的分配,因为字符串将具有足够的容量来容纳对象。这减少了对new
和delete
的调用。
编写接口。
append_to
有一个后备功能,它使用to_string
,以及许多针对不同容器的专门化。专门化将是向前声明的,因此它们彼此可见。
后退。
这个版本是专门化程度最低的,只有在没有其他方法附加对象时才会启用。我们使用SFINAE来检查to_string
方法的存在。
这个方法可以来自命名空间std;它可以在全局命名空间中定义,甚至可以在与用户定义类型相同的命名空间中定义to_string
to_string
。在最后一种情况下,编译器通过ADL (参数相关查找)找到它。
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
函数,但是为它们编写高效的追加函数很简单。
// 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容器和类型的正向声明
向前声明它们是一个好主意,因为这样做将允许它们相互调用。
// 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 the
append_rangefunction to implement
append_to`作为append_range
容器的STL函数。
// 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中引入)将元组扩展为参数包。一旦我们有了它,我们就可以使用一个折叠表达式来附加每个元素。
// 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 += ')';
}
}
添加一个对也是非常简单的:
// 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
。
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会自动找到它。
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 += '>';
}
}
在您的库中使用此代码
我们可以很容易地为Table
编写一个append_to
函数!
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
https://stackoverflow.com/questions/56451865
复制相似问题