可变参数
C++ Variadic parameters
我正在设计一个方便的配置对象,它将从文件中加载配置值。为了确保有相同的默认值,程序员可以为每种类型的值声明它的类型和默认值。这样,就可以检查配置文件,并立即发现任何不正确的地方。例如,考虑以下配置文件httpd.conf:
port 8080
htdocs ROOT
prelude true
和main中的配置对象:
int main() {
Config conf("httpd.conf",
"port", Config::INT, 80,
"htdocs", Config::STRING, "default/",
"preload", Config::BOOLEAN, false);
上面的代码将加载文件并验证port实际上是一个整数,它将加载htdocs,并发现文件中的"prelude"与配置中的任何注册值都不匹配,并发出一个错误:
第3行:未定义配置项"prelude"
我可以用一个旧的C可变参数来实现上述功能,但这些参数不是类型安全的。有什么方法可以用新的c++可变参数做到这一点吗?我所看到的例子都是千篇一律的。这里是值的三元组
我想设计一些易于在单个大调用中编写的东西,但这是类型安全的
如果不使用可变模板或函数并避免类型省略,您可能会:
#include <sstream>
#include <stdexcept>
class Configuration
{
public:
Configuration(const std::string& resource)
// Initialize the resources: Program options, environment variables, files
{}
/// Get a raw configuration value for a key.
/// Reurns true if the key exists
bool get_raw(const std::string key, std::string& result) const {
// Find the key in supplied resources and set the result string
// trimming leading and trailing spaces
return false;
}
template <typename T>
T get(const std::string key) const;
template <typename T>
T get(const std::string key, const T& default_value) const;
};
template <typename T>
T Configuration::get(const std::string key) const {
std::string str;
if( ! get_raw(key, str)) throw std::runtime_error("Invalid Key");
else {
T result;
std::istringstream is(str);
is.unsetf(std::ios_base::basefield);
is >> result;
if( ! is.eof() || is.fail()) throw std::runtime_error("Invalid Value");
return result;
}
}
template <typename T>
T Configuration::get(const std::string key, const T& default_value) const {
std::string str;
// There might be a dilemma - is a non existing key an error?
if( ! get_raw(key, str)) return default_value;
else if(str.empty()) return default_value;
else {
T result;
std::istringstream is(str);
is.unsetf(std::ios_base::basefield);
is >> result;
if( ! is.eof() || is.fail()) throw std::runtime_error("Invalid Value");
return result;
}
}
// Usage
struct HttpConfiguration : public Configuration
{
unsigned port;
std::string htdocs;
bool preload;
HttpConfiguration()
: Configuration("httpd.conf"),
port(get<unsigned>("port", 80)),
htdocs(get<std::string>("htdocs", "default/")),
preload(get<bool>("prelude", false)) // typo here
{}
};
注意:类配置可以是任何管理配置源(看看Boost, POCO,…)。
如果你想使用可变模板,这只是一个开始:
template <class T>
struct Param {
using Type = T;
std::string name_;
T default_value_;
};
template <class T>
auto MakeParam(std::string name, T default_value) -> Param<T> {
return {name, default_value};
}
template <class T, class... Args>
auto ReadParams(Param<T> p, Args... args) -> void {
ReadParams(p);
ReadParams(args...);
}
template <class T>
auto ReadParams(Param<T> p) -> void {
// here you can read from file
cout << "param: '" << p.name_ << "' type: '"
<< typeid(typename Param<T>::Type).name() << "' defval: '"
<< p.default_value_ << "'" << endl;
}
int main() {
ReadParams(MakeParam("param1", 0), MakeParam("param2", true),
MakeParam("param3", "c-string"),
MakeParam("param4", std::string{"c++str"}));
return 0;
}
相关文章:
- 在不传递参数数量且只有3个点的情况下,如何使用变差函数
- 如何使用可变参数模板强制转换每个变体类型
- 关于如何在具有单个参数的变体构造中选择替代方案?
- 调用参数排列不变函数 f(i++, i++)
- 参数归纳与标准::变体
- 模板化回调参数的逆变,如 C# 中的逆变
- 如何在没有参数包的情况下编写变差函数
- 通过具有嵌套类的工厂类获取多个变异类模板参数包
- 获取模板参数的成员变量值列表
- 保留短 lambda 用作函数的中间参数,使用 clang 格式保持不变
- 如何定义变体<x,y,z>提取模板参数的子类型
- 正确对齐内存模板,参数顺序不变
- 递归中不同参数类型的变元模板函数
- 通过函数指针传递给变差函数的参数会更改其值
- 提升预定义为带有参数的全局 lambda 的变体访问者
- 使用可变参数模板参数提升变体访问者
- boost ::变体 - 为什么模板参数比const字符串参数具有更高的优先级
- 将变参数包中的值加载到临时数组中
- 使用额外参数提升变体访客
- 正在将动态数组元素解析为参数?(变音符)