我仍在尝试将较旧的程序更新为现代C ++,但是我还有另一个与模板有关的问题。 我正在使用libconfig ++处理程序配置,将纯文本数据写入配置文件。 您可以选择要写入文件的数据类型,并且库使用枚举来执行此操作(即Setting :: TypeString,Setting :: TypeBoolean等)
起初,我使用普通的重载,如下所示:
void Config::write_value(Setting& root, const string& key, const string& value) {
if (!root.exists(key.c_str())) root.add(key.c_str(), Setting::TypeString) = value;
else {
Setting& s = root[key.c_str()];
s = value;
}
}
void Config::write_value(Setting& root, const string& key, const bool value) {
if (!root.exists(key.c_str())) root.add(key.c_str(), Setting::TypeBoolean) = value;
else {
Setting& s = root[key.c_str()];
s = value;
}
}
但是这些函数是通用处理的候选对象,因为只需更改一个参数,就可以从该参数推导出库使用的类型。
问题是:我该怎么办? 我尝试使用conditional_t和is_same,但是编译器对我尝试的操作不满意,出了点问题,我认为这与枚举有关……
将枚举映射到参数类型的正确方法是什么?
这是我尝试过的一件事:
template<typename T>
using Type = std::conditional_t<std::is_same_v<T, bool>, Setting::TypeBoolean, void>;
template<typename T>
void write_value(libconfig::Setting& root, const std::string& key, const T& value)
{
if (!root.exists(key.c_str())) root.add(key.c_str(), Type<T>) = value;
else {
Setting& s = root[key.c_str()];
s = value;
}
}
// Compiler error :
error C2275: 'Config::Type<bool>' : illegal use of this type as an expression
感谢您的阅读:)
编辑 Setting :: *是一个枚举,实际上定义为Setting :: Type。
enum Type
{
TypeNone = 0,
// scalar types
TypeInt,
TypeInt64,
TypeFloat,
TypeString,
TypeBoolean,
// aggregate types
TypeGroup,
TypeArray,
TypeList
};
答案 0 :(得分:2)
您在这里不解释对象root.add()如何从任意类型分配,但这似乎不是您当前要我们解决的问题...
您当前要解决的问题是将模板类型具体翻译为适当的枚举索引,为此,在c ++ 11中,我只需定义一个翻译器类即可:
template <class T> class ToMySetting {};
template <> ToMySetting<int> { static Setting index = {Setting::TypeInt}; };
template <> ToMySetting<char*> { static Setting index = {Setting::TypeCStr}; };
template <> ToMySetting<bool> { static Setting index = {Setting::TypeBool}; };
然后您可以将write_value
函数中的内容用作ToMySetting<T>::index
在较新的版本(c ++ 17)中,我倾向于使用if constexpr
语法仅一次定义ToMySetting转换器类主体。
答案 1 :(得分:0)
在根据@ gem-taylor答案进行了一些研究之后,我得到了下面的版本,该版本可以根据需要工作。仍需要进行一些调整以包括std :: string版本,但这不是必需的。
{ 'year': 2018, 'month': 6, 'day': 14 }
编辑:为完整起见,这是char数组和std :: string的2个专业化:
template <class T> struct ToMySetting;
template <> struct ToMySetting<bool> { static constexpr libconfig::Setting::Type index = libconfig::Setting::TypeBoolean; };
template <> struct ToMySetting<uint32_t> { static constexpr libconfig::Setting::Type index = libconfig::Setting::TypeInt; };
template <> struct ToMySetting<uint64_t> { static constexpr libconfig::Setting::Type index = libconfig::Setting::TypeInt64; };
template <> struct ToMySetting<float> { static constexpr libconfig::Setting::Type index = libconfig::Setting::TypeFloat; };
template <> struct ToMySetting<const char*> { static constexpr libconfig::Setting::Type index = libconfig::Setting::TypeString; };
template<class T>
void write_value(libconfig::Setting& root, const std::string& key, const T& value)
{
if (!root.exists(key.c_str())) root.add(key.c_str(), ToMySetting<T>::index) = value;
else {
libconfig::Setting& s = root[key.c_str()];
s = value;
}
}