Я столкнулся с проблемой при использовании boost::property_tree
, которая, вероятно, имеет более общие приложения.Моя цель состояла в том, чтобы создать функцию загрузчика, которая способна выбрать правильный загрузчик в зависимости от расширения файла.Мое решение состоит в использовании последовательных if else-if
утверждений:
auto extension = input_filename.extension().string();
if(iequals(extension, ".json")) pt::read_json(input_filename.string(), tree);
else if(iequals(extension, ".info")) pt::read_info(input_filename.string(), tree);
else if(iequals(extension, ".xml")) pt::read_xml(input_filename.string(), tree);
else if(iequals(extension, ".ini")) pt::read_ini(input_filename.string(), tree);
else ... // unknown file type
Я думаю, что должно быть лучшее решение, чем это.Если я вспоминаю Python, где вы можете сделать что-то вроде map<extension, function>[extension](input_filename.string(), tree)
, это вдохновило меня на следующее.Идея заключалась в том, чтобы использовать карту для создания связи между строкой расширения и функцией:
using loader_fct = void(*)(const std::string &, pt::ptree &, const std::locale &);
using loader_table = std::map<std::string, loader_fct>;
const loader_table load_funct{
{".json", &pt::read_json},
{".ini", &pt::read_ini},
{".info", &pt::read_info},
// {".xml", &pt::read_xml}
};
Первая проблема заключалась в том, что, очевидно, не все функции загрузчика (-templates) имели одинаковую сигнатуру, поэтомумы не можем использовать XML.Кроме того, мы должны определить все аргументы шаблона, затем мы можем использовать его следующим образом:
auto extension = boost::to_lower_copy(input_filename.extension().string());
auto loader = load_funct.find(extension);
loader->second(input_filename.string(), tree, std::locale());
Мне удалось решить проблему с различными сигнатурами функций с помощью некоторых шаблонов, которые позволяют намчтобы упростить немного больше:
template<typename Ptree>
void read_json(const std::string & s, Ptree & t) { pt::read_json(s, t); }
template<typename Ptree>
void read_ini(const std::string & s, Ptree & t) { pt::read_ini(s, t); }
template<typename Ptree>
void read_info(const std::string & s, Ptree & t) { pt::read_info(s, t); }
template<typename Ptree>
void read_xml(const std::string & s, Ptree & t) { pt::read_xml(s, t); }
using loader_table = std::map<std::string, void(*)(const std::string &, pt::ptree &)>;
loader_table load_funct{
{".json", &read_json},
{".ini", &read_ini},
{".info", &read_info},
{".xml", &read_xml}
};
auto extension = boost::to_lower_copy(input_filename.extension().string());
if(load_funct.count(extension))
{
load_funct[extension](input_filename.string(), tree);
}
Мой основной вопрос:
Есть ли лучшие способы сделать это?Или другие идеи?
Последнее решение заставило меня задуматься, есть ли возможность сделать выбор правильного загрузчика уже в шаблоне?