[英]C++ Variadic parameters
I am designing a convenient config object which will load config values from a file. 我正在设计一个方便的配置对象,该对象将从文件中加载配置值。 In order to make sure there are sane defaults, the programmer can state for each kind of value what type it is, and a default value. 为了确保有合理的默认值,程序员可以为每种值声明其类型和默认值。 That way, the config file can be checked and any incorrect can be immediately found. 这样,可以检查配置文件,并且可以立即发现任何错误。 For example, consider the following config file httpd.conf: 例如,考虑以下配置文件httpd.conf:
port 8080
htdocs ROOT
prelude true
and a config object in main: 和main中的配置对象:
int main() {
Config conf("httpd.conf",
"port", Config::INT, 80,
"htdocs", Config::STRING, "default/",
"preload", Config::BOOLEAN, false);
The above code would load the file and verify that port is in fact an integer, it would load htdocs , and it would find that "prelude" in the file does not match any registered value in the config, and emit an error: 上面的代码将加载文件并验证port实际上是整数,它将加载htdocs,并且将发现文件中的“ prelude”与配置中的任何注册值都不匹配,并发出错误消息:
line 3: undefined configuration item "prelude" 第3行:未定义的配置项目“前奏”
I could implement the above with an old C variadic parameters, but those are not typesafe. 我可以使用旧的C可变参数实现上述功能,但这些参数不是类型安全的。 Is there any way to do it with the new C++ variadic parameters? 有什么办法可以使用新的C ++可变参数吗? The examples I have seen are all monotyped. 我所看到的例子都是单类型的。 Here I have triples of values. 在这里,我拥有三倍的价值。
I would like to design something that is easy to write in a single large call, but that is typesafe. 我想设计一个易于在单个大调用中编写的东西,但这是类型安全的。
Without using variadic templates or functions and avoiding type elision you might do: 在不使用可变参数模板或函数且避免类型省略的情况下,您可以执行以下操作:
#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
{}
};
Note: The class configuration can be anything managing configuration sources (have a look at Boost, POCO, ...). 注意:类配置可以是管理配置源的任何内容(请查看Boost,POCO等)。
Just to get you started if you want to use variadic templates: 如果您想使用可变参数模板,请入门:
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.