Question

How do I get an enum from a boost::property_tree?

This is my "non-working" example.

config.xml

<root>
  <fooEnum>EMISSION::EMIT1</fooEnum>
  <fooDouble>42</fooDouble>
</root>

main.cpp

#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

int main()
{
  enum class EMISSION { EMIT1, EMIT2 } ;
  enum EMISSION myEmission;

  //Initialize the XML file into property_tree
  boost::property_tree::ptree pt;
  read_xml("config.xml", pt);

  //test enum (SUCCESS)
  myEmission = EMISSION::EMIT1;
  std::cout << (myEmission == EMISSION::EMIT1) << "\n";

  //test basic ptree interpreting capability (SUCCESS)
  const double fooDouble = pt.get<double>("root.fooDouble");
  std::cout << fooDouble << "\n";

  //read from enum from ptree and assign (FAILURE)
  myEmission = pt.get<enum EMISSION>( "root.fooEnum" );
  std::cout << (myEmission == EMISSION::EMIT1) << "\n";

  return 0;
}

Compile Output

/usr/include/boost/property_tree/stream_translator.hpp:36:15: 
error: cannot bind 'std::basic_istream<char>' lvalue to 
'std::basic_istream<char>&&'

/usr/include/c++/4.8/istream:872:5: error:   
initializing argument 1 of 'std::basic_istream<_CharT, 
  _Traits>& std::operator>
(std::basic_istream<_CharT, _Traits>&&, _Tp&)
[with _CharT = char; _Traits = std::char_traits<char>;
_Tp = main()::EMISSION]'
Was it helpful?

Solution

The name of an enum in C++ is a symbol, not a string. There isn't a way to map between a string and an enum value unless you provide that mapping yourself by writing a method such as:

EMISSION emission_to_string(const std::string& name)
{
    if ( name == "EMISSION::EMIT1")
    {
        return EMISSION::EMIT1;
    }
    ... etc
}

You would then get the value as a string from the property_tree and apply this mapping.

There are nicer ways to implement this which scale more elegantly with many enum values. I have done this using boost::bimap to enable a mapping from enum->string OR from string->enum, and of course this also gives you a map instead of a silly big if statement. If you do this, look into using boost::assign to initialise your static map, as it looks cleaner than other methods.

OTHER TIPS

The mapping between string and enum has to be done by hand. However, you can implement a translator for the enum as descibed here: http://akrzemi1.wordpress.com/2011/07/13/parsing-xml-with-boost/

Having this, you can conveniently write

myEmission = pt.get<EMISSION>("root.fooEnum");
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top