Je me suis égaré dans les fichiers d’en-tête de boost property_tree et, en raison du manque de documentation sur les couches inférieures, j’ai décidé de demander quelle était la méthode la plus simple pour contourner le traducteur de stream afin de changer la façon dont les valeurs booléennes sont analysées.
Le problème est que du côté entrée d’un arbre de propriétés, il y a des utilisateurs qui peuvent modifier les fichiers de configuration. Une valeur booléenne peut être spécifiée de plusieurs manières, par exemple:
dosomething.enabled=true dosomething.enabled=trUE dosomething.enabled=yes dosomething.enabled=ON dosomething.enabled=1
Le comportement par défaut consiste à vérifier 0 ou 1, puis à utiliser
std::ios_base::boolalpha
pour que le stream tente d’parsingr la valeur de la manière appropriée pour les parameters régionaux en cours … ce qui peut paraître insensé si nous essayons d’envoyer un fichier de configuration à des clients internationaux.
Alors, quel est le moyen le plus simple d’annuler ce comportement ou de le bool uniquement? Non seulement la plus facile à implémenter, mais la plus facile à utiliser – de sorte que les utilisateurs de ma classe qui dérivent de iptree n’aient pas besoin de faire quelque chose de spécial pour les valeurs booléennes.
Merci!
Vous pouvez spécialiser boost::property_tree::translator_between
afin qu’une arborescence de propriétés utilise un traducteur personnalisé pour un type de valeur bool
. Cette spécialisation doit être visible (c.-à-d. #includ
ed) par les clients souhaitant le comportement personnalisé. Voici un exemple de travail:
#include #include #include #include // Custom translator for bool (only supports std::ssortingng) struct BoolTranslator { typedef std::ssortingng internal_type; typedef bool external_type; // Converts a ssortingng to bool boost::optional get_value(const internal_type& str) { if (!str.empty()) { using boost::algorithm::iequals; if (iequals(str, "true") || iequals(str, "yes") || str == "1") return boost::optional (true); else return boost::optional (false); } else return boost::optional (boost::none); } // Converts a bool to ssortingng boost::optional put_value(const external_type& b) { return boost::optional (b ? "true" : "false"); } }; /* Specialize translator_between so that it uses our custom translator for bool value types. Specialization must be in boost::property_tree namespace. */ namespace boost { namespace property_tree { template struct translator_between, bool> { typedef BoolTranslator type; }; } // namespace property_tree } // namespace boost int main() { boost::property_tree::iptree pt; read_json("test.json", pt); int i = pt.get("number"); int b = pt.get("enabled"); std::cout << "i=" << i << " b=" << b << "\n"; }
test.json:
{ "number" : 42, "enabled" : "Yes" }
Sortie:
i=42 b=1
Veuillez noter que cet exemple suppose que l'arborescence des propriétés ne respecte pas la casse et utilise std::ssortingng
. Si vous souhaitez que BoolTranslator
soit plus général, vous devez en faire un modèle et fournir des spécialisations pour les chaînes larges et les comparaisons sensibles à la casse.
Il existe également un bon exemple sur theboostcpplibraries.com .
Sur cette base, j’ai écrit pour un parsingur personnalisé (déclaration omise):
boost::optional ssortingng_to_bool_translator::get_value(const std::ssortingng &s) { auto tmp = boost::to_lower_copy(s); if (tmp == "true" || tmp == "1" || tmp == "y" || tmp == "on") { return boost::make_optional(true); } else if (tmp == "false" || tmp == "0" || tmp == "n" || tmp == "off") { return boost::make_optional(false); } else { return boost::none; } }
C’est seulement pour bool et std :: ssortingng mais facilement extensible.
Ensuite,
boost::property_tree::ptree pt; ... ssortingng_to_bool_translator tr; auto optional_value = pt.get_optional(key, tr);