Change how boost::property_tree reads translates strings to bool

前端 未结 2 1097
终归单人心
终归单人心 2020-12-29 10:07

I\'ve gotten lost in the header files for the boost property_tree and given the lack of documentation around the lower layers, I\'ve decided to ask what the easy way is to o

相关标签:
2条回答
  • 2020-12-29 10:12

    You can specialize boost::property_tree::translator_between so that a property tree will use a custom translator for a bool value type. This specialization must be visible (i.e. #included) by clients wanting the customized behavior. Here's a working example:

    #include <iostream>
    #include <boost/property_tree/ptree.hpp>
    #include <boost/property_tree/json_parser.hpp>
    #include <boost/algorithm/string/predicate.hpp>
    
    // Custom translator for bool (only supports std::string)
    struct BoolTranslator
    {
        typedef std::string internal_type;
        typedef bool        external_type;
    
        // Converts a string to bool
        boost::optional<external_type> 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<external_type>(true);
                else
                    return boost::optional<external_type>(false);
            }
            else
                return boost::optional<external_type>(boost::none);
        }
    
        // Converts a bool to string
        boost::optional<internal_type> put_value(const external_type& b)
        {
            return boost::optional<internal_type>(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<typename Ch, typename Traits, typename Alloc> 
    struct translator_between<std::basic_string< Ch, Traits, Alloc >, 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<int>("number");
        int b = pt.get<bool>("enabled");
        std::cout << "i=" << i << " b=" << b << "\n";
    }
    

    test.json:

    {
        "number" : 42,
        "enabled" : "Yes"
    }
    

    Output:

    i=42 b=1
    

    Please note that this example assumes that the property tree is case insensitive and uses std::string. If you want BoolTranslator to be more general, you'll have to make BoolTranslator a template and provide specializations for wide strings and case sensitive comparisons.

    0 讨论(0)
  • 2020-12-29 10:17

    There is also a good example at theboostcpplibraries.com.

    Based on that, I wrote for a custom parser (declaration omitted):

    boost::optional<bool> string_to_bool_translator::get_value(const std::string &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;
        }
    } 
    

    It's only for bool and std::string but easily extendable.

    Then,

    boost::property_tree::ptree pt;
    ...
    string_to_bool_translator tr;
    auto optional_value = pt.get_optional<bool>(key, tr);
    
    0 讨论(0)
提交回复
热议问题