前言
- 写这个文章的目的,还是因为在网上没有找到合适的资料,所以自己来写一个
- toml11简中的资料是在是太少.你去搜吧,能看的资料几乎没有.这也是我写这个文章的缘由.说白了还是用的人太少了.
- 官方的文档也是"过于简洁".只有github上的一个readme可以参考.资料太少就会导致你的开发周期被加长,时间被浪费.
- 你要是读文件还行, 也比较简单,但是一旦牵扯到格式转化,这个库也做不到,和我之前用的boost解析json确实有一些差距,所以我简单实现了一下.
- 比如toml中的布尔量,你定义一个a,a=false,这么写是可以;但是你,a=0;这种情况下,toml11却无法解析.这种情况下你给同事使用,无疑是增加了学习成本.
- 另外就是写数据到toml中,这个在toml11的文档中资料很少,简中一点都没搜到.我的文档中会对这个也有介绍.
- 针对上面所说的问题,这也是写这个文档的缘由.
官方资料
具体的还是看这个,怎么说这个是官方的资料
ToruNiina/toml11: TOML for Modern C++ (github.com)
读文件
toml::get_or
toml::get_or 函数用于从 toml::value 对象中获取指定键的值。 如果键存在,则返回相应的值; 如果键不存在,则返回用户提供的默认值。
toml::get_or<double>(data, "a", 0.1)
表示获取键为 "a" 的值,如果存在则返回对应的浮点数值,如果不存在则返回默认值 0.1。
需要注意的是,使用 toml::get_or 的前提是你能够确定配置项的类型,并且在键不存在时能够提供一个合适的默认值。
如果你无法确定类型或者默认值是无法确定的,可以使用其他处理方式,比如手动检查键是否存在 ,然后根据情况再使用 toml::find 或 toml::find_or。
toml::find_or
在 toml11 库中,toml::find_or 函数用于从 toml::value 对象中获取指定键的值。
toml::find_or<double>(data, "a", 0.1)
表示获取键为 "a" 的值,如果存在则返回对应的浮点数值,如果不存在则返回默认值 0.1。
要注意的是:
toml文件中a=1.0,为浮点数。这么读肯定是没有问题的,toml::find_or<double>(data, "a", 0.1)
如果配置项不存在,就是默认值0.1如果配置项不是浮点数,他也是默认值。!!!这个要注意下
type
返回读取toml配置项的类型
auto valueType = toml::find(data, key).type();
find
在 toml11 中,toml::find 函数用于从 toml::value 对象中获取指定键的值。
template<typename T>
T find(const toml::value& v, const std::string& key);
不能指定默认参数
[fruit]
name = "apple"
[fruit.physical]
color = "red"
shape = "round"
const auto data = toml::parse("fruit.toml");
//当读取的不是具体条目的时候,不用指定类型
const auto& fruit = toml::find(data, "fruit");
//当读取的是具体条目的时候,需要指定类型——如果类型和toml中的类型不对的话,就会造成程序退出。内部是不会进行类型转换
const auto name = toml::find<std::string>(fruit, "name");
写
demo1
#include <toml.hpp>
#include <iostream>
#include <fstream>
int main() {
// 创建一个 TOML 表
toml::value data{
{"title", "example"},
{"owner", toml::value{
{"name", "Tom Preston-Werner"},
{"dob", "1979-05-27"}
}},
{"database", toml::value{
{"server", "192.168.1.1"},
{"ports", toml::array{8001, 8001, 8002}},
{"connection_max", 5000},
{"enabled", true}
}}
};
// 将 TOML 表写入文件
std::ofstream ofs("example.toml");
ofs << data;
// 检查写入是否成功
if (ofs.good()) {
std::cout << "Data successfully written to example.toml" << std::endl;
}
else {
std::cerr << "Error writing to example.toml" << std::endl;
}
return 0;
}
结果
title = "example"
[owner]
name = "Tom Preston-Werner"
dob = "1979-05-27"
[database]
server = "192.168.1.1"
ports = [
8001,
8001,
8002,
]
connection_max = 5000
enabled = true
demo2
void writeToml()
{
// 创建一个 TOML 文档
toml::value doc;
// 添加一些键值对、数组和表
doc["key1"] = 42; // 整数
doc["key2"] = 3.14; // 浮点数
doc["key3"] = "hello"; // 字符串
toml::array arr;
arr.push_back(1);
arr.push_back(2);
doc["my_array"] = arr; // 数组
toml::value nested_table;
nested_table["nested_key"] = "world";
doc["nested"] = nested_table; // 表
// 将文档输出为 TOML 字符串
std::string toml_str = toml::format(doc);
// 将 TOML 字符串写入文件
std::ofstream file("./example.toml");
file << toml_str;
file.close();
return;
}
结果
key1 = 42
key2 = 3.1400000000000001
key3 = "hello"
my_array = [1,2]
nested = {nested_key="world"}
多层嵌套
这个真是麻烦,而且也找不到资料,官方文档里也没怎么写。
我当时写的时候也是非常费劲,我这边是双层map遍历,牵扯到读,写,修改,以及判断某些配置项是否存在,并且和map同步确实有点复杂。
我就两个建议,如果你不是非toml必选,我建议你换。toml是很好,toml11我觉得还是差点。
另外就是问AI,但根据我的经验来看,你问大概率也是不对的,需要花一段改。这本质上还是因为toml11的资料少,投喂AI训练也不够。
格式转化
编译器最低支持C++17,才能编译.
支持默认值.支持类型转换,
使用方法:
配置文件
a="1"
b=0;
#c未在配置文件中
demo
//data:toml的toml::value key:toml的中配置项 default_value:该配置项的默认值
GetTomlValue(const toml::value &data, const std::string &key, const T &default_value)
int a= GetTomlValue<int>(data, "a", 200);//a在toml中是字符,这里转换成int类型读出来
bool b = GetTomlValue<bool>(data, "b", false);//b在toml中是是整形,这里转换成bool类型读出来
float c = GetTomlValue<bool>(data, "c",1.1);//c在toml中不存在,这里给c赋值默认值1.1
源码:
template <typename T>
T GetTomlValue(const toml::value &data, const std::string &key)
{
if (!(is_same_v<T, string> || is_same_v<T, int> || is_same_v<T, unsigned int> || is_same_v<T, unsigned long long> || is_same_v<T, float> || is_same_v<T, bool>))
{
LogError("Toml文件函数模板,目前只处理了string,int,unsigned int,unsigned long long,float,bool这四个常用类型。其他类型手动添加下即可");
exit(-1);
}
auto valueType = toml::find(data, key).type();
switch (valueType)
{
case toml::value_t::integer:
{
unsigned long long value = toml::find<unsigned long long>(data, key);
if constexpr (is_same_v<std::decay_t<T>, int> || is_same_v<T, unsigned int> || is_same_v<T, unsigned long long> || is_same_v<T, float> || is_same_v<T, bool>)
return value;
else {
LogError(key + "TOML文件类型转化,不支持从int转化到" + (string) typeid(T).name());
exit(-1);
}
}
break;
case toml::value_t::floating:
{
float value = toml::find<float>(data, key);
if constexpr (std::is_same_v<std::decay_t<T>, float>) // 想要的是float
return value;
else if constexpr (std::is_same_v<std::decay_t<T>, int>) // 想要的是int
return static_cast<int>(value);
else {
LogError(key + "TOML文件类型转化,不支持从float转化到" + (string) typeid(T).name());
exit(-1);
}
}
break;
case toml::value_t::string:
{
string value = toml::find<string>(data, key);
if constexpr (std::is_same_v<std::decay_t<T>, string>) // 想要的是string
return value;
else if constexpr (std::is_same_v<std::decay_t<T>, int>)
return stoi(value);
else if constexpr (std::is_same_v<std::decay_t<T>, unsigned int>)
return stoul(value);
else if constexpr (std::is_same_v<std::decay_t<T>, unsigned long long>)
return stoull(value);
else if constexpr (std::is_same_v<std::decay_t<T>, float>)
return stof(value.c_str());
else if constexpr (std::is_same_v<std::decay_t<T>, bool>)
{
if (value == "1" || value == "0")
return atoi(value.c_str());
else if (value == "true")
return 1;
else if (value == "false")
return 0;
else
{
LogError("Toml文件配置项,布尔量" + key + "=" + value + ",应该在0,1或true,false选择");
exit(-1);
}
}
else {
LogError(key + "TOML文件类型转化,不支持从string转化到" + (string) typeid(T).name());
exit(-1);
}
break;
}
case toml::value_t::boolean:
{
if constexpr (std::is_same_v<std::decay_t<T>, bool>)
return toml::find<bool>(data, key);
else {
LogError(key + "TOML文件类型转化,不支持从bool转化到" + (string) typeid(T).name());
exit(-1);
}
}
break;
// 其他类型的处理
default:
LogError("TOML文件类型转化,我做的GetTomlValue函数模板,不支持这个类型,可以尝试练习我做个适配!");
exit(-1);
break;
}
return 0;
}
template <typename T>
T GetTomlValue(const toml::value &data, const std::string &key, const T &default_value)
{
return data.contains(key) ? GetTomlValue<T>(data, key) : default_value;
}