如果你学过主流编程语言的话,这里的键值对应该会让你想起那么几个词: map、hash、dictionary 等等
在程序员的世界里,键值对其实就是我们的映射。比如在 C++ 里,我们要存储这样的数据就使用 std::map 即可。
也就是说,我们的 Config 类中,需要有一个最基本最基本的存储配置文件键值对信息的 std::map 成员,这个成员用来将配置文件中的每个 key 值和其对应的 value 值记录下来。
那么另外一个问题也就来了,我们的 std::map 究竟应该是什么类型的呢?
哈哈,这个问题其实非常简单,因为我们的键值对信息都是要读出写入到文件的,那么 std::map 不论是 key 值还是 value 值都将会是字符串类型,即 C++ STL 的 std::string (Config 类不支持中文编码)类即可。
那么有人就会问了,如果 value 值只是一个简简单单的 std::string 类的话,我想要存储一个非常复杂的数据结构怎么办,比如一个 phone key 值,对应了一个电话号码列表呢?
这个问题其实也非常简单,这里的 std::map 成员只是 Config 类中的最基本最基本存储到文件里的字符串键值对记录,而 Config 为了支持用户存储多种复杂的 value 值,还提供了模板支持。因此,这里只需要你提供的 value 值的结构可以被转化为 std::string 类型,就可以使用 Config 类来存储你的数据结构了。
因此,让我们看看 Config 类的代码:
std::string m_Delimiter; //!< separator between key and value std::string m_Comment; //!< separator between value and comments std::map<std::string, std::string> m_Contents; //!< extracted keys and values
此外,我们在 Config 类中看到的那么多的模板函数,其归根结底想要实现的,就是支持用户自定义的 value 数据结构的读取和写入:
//!<Search for key and read value or optional default value, call as read<T> template<class T> T Read(conststd::string& in_key) const;
// Modify keys and values template<class T> void Add(conststd::string& in_key, const T& in_value);
这里截取了两个重要的函数,一个用来读取 key 值对应的 value 值,一个用来添加一个键值对。可以看到,这里的 key 值永远都是一个 std::string 类型的对象,而相应的 value 值则是模板定义的类型,支持用户自定义传入任何的可以转成 std::string 类型的数据结构。
/* static */template<class T>
std::string Config::T_as_string(const T& t)
{
// Convert from a T to a string // Type T must support << operator std::ostringstream ost;
ost << t;
return ost.str();
}
这个类直接调用了用户自定义模板类的 operator<< 重载操作符函数,也就是说,只要用户自定义数据结构自定义重载了 operator<< 操作符函数,就可以用 Config 类来进行 value 值的读写操作了。
5. 删除一对键值对
void Config::Remove(conststring& key)
{
// Remove key and its value
m_Contents.erase(m_Contents.find(key));
return;
}