Search code examples
c++templatesboostdynamic-propertiesboost-property-map

How to use `boost::dynamic_properties` with vector valued property maps?


I would like to include a map<string, vector<int>> in a boost::dynamic_properties property:

#include <map>
#include <string>
#include <vector>

#include <boost/property_map/dynamic_property_map.hpp>
#include <boost/property_map/property_map.hpp>

auto main() -> int {
  auto name2numbers = std::map<std::string, std::vector<int>>{};
  auto property_map = boost::associative_property_map{name2numbers};
  auto dynamic_properties = boost::dynamic_properties{};
  dynamic_properties.property("test", property_map);
}

Compiling with g++ fails with the error no match for ‘operator<<’ for ostringstream and vector<int>:

error: no match for ‘operator<<’ (operand types are ‘std::ostringstream’ {aka ‘std::__cxx11::basic_ostringstream<char>’} and ‘boost::associative_property_map<std::map<std::__cxx11::basic_string<char>, std::vector<int> > >::value_type’ {aka ‘std::vector<int>’})
  180 |     out << get_wrapper_xxx(property_map_, any_cast<typename boost::property_traits<PropertyMap>::key_type>(key_));
      |     ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

So I decided to add a template for general vector streaming above main:

template <typename OStream>
auto operator<<(OStream& output_stream, std::vector<int> const& vec)
    -> OStream& {
  for (auto item : vec) {
    output_stream << item << " ";
  }
  return output_stream;
}

Unfortunately, that does not help. Neither does writing a function explicitly for ostringstream. I always get the same error and my template does not appear in the list of candidates tried by the compiler. How can I actually tell boost::dynamic_properties how to write a vector of integers or at least make it try my template?


Solution

  • If you want to “hack” solution by providing operator<< for a standard library type, you need to declare it in one of the associated namespaces for argument dependent lookup. Specifically you would need to declare this overload inside namespace std (because both std::vector and std::o stream are declared there).

    However I would suggest taking more control over the specific serialization format of your property-map by using a transform_value_propertymap or function_property_map instead.

    See for some examples:

    A search on this site will probably reveal more relevant answers by yours truly