yaml-cpp

Defining custom input types for the new yaml-cpp API


I am trying to define some custom input types using the new-style YamlCpp API. I have two questions. Let me first say that we are currently using the 0.3 style-api and everything works great. The code-appearance of the new API is about 10x better though so we wanted to move to it.

  1. Why does my current approach bork the compiler?
  2. Is yaml-cpp smart enough to handle nested templates. For example, if my parser knows how to enc/dec std::vectors, and then I define a custom handler for MyAwesomeType separately -- can I ask it to enc/dec a std::vector<MyAwesomeType> and it will figure it out?

My code began by copying and pasting the example on the website (here) and then modifying that. My current implementation attempts to handle conversion of std::vector<std::pair<qint16,qint16>> -- this does not compile. (fyi - qint16 is simply a cross-platform typedef for __int16)

    #include "yaml-cpp\yaml.h"
    #include <vector>
    #include "qglobal.h"
    
    namespace YAML {
       // a std::pair of qint16's
       template<>
       struct convert<std::pair<qint16,qint16>> {
          static Node encode( std::pair<qint16,qint16> const& rhs) {
             Node node;
             std::vector<qint16> newVec;
             newVec.push_back(rhs.first);
             newVec.push_back(rhs.second);
             node = newVec;
             return node;
          }
          static bool decode(Node const& node, std::pair<qint16,qint16> & rhs) {
             if(!node.IsSequence() || node.size() != 2) {
                return false;
             }
    
             rhs.first = node[0].as<qint16>();
             rhs.second = node[1].as<qint16>();
             return true;
          }
       };
    
       // a vector of std::pair of qint16's
       template<>
       struct convert<std::vector<std::pair<qint16,qint16>>> {
          static Node encode( std::vector<std::pair<qint16,qint16>> const& rhs) {
             Node node;
             for(auto pairIt=rhs.begin();pairIt!=rhs.end();++pairIt)
             {
                 node.push_back( *pairIt );
             }
             return node;
          }
          static bool decode(Node const& node, std::vector<std::pair<qint16,qint16>> & rhs) {
             if( !node.IsSequence() ) {
                return false;
             }
    
             for(int k=0;k<node.size();++k)
             {
                 rhs.push_back( node[k].as<std::pair<qint16,qint16>>() );
             }
             return true;
          }
       };
    }

Finally, I would like to then use this to call

    std::map<std::string, std::vector<std::pair<qint16, qint16>>> m_vectorOfPairs;
    if( doc["myPairs"] )
    {
        // key exists!
        for( YAML::const_iterator it=doc["myPairs"].begin();it!=doc["myPairs"].end();++it)
        {
            m_vectorOfPairs[it->first.as<std::string>()] = it->second.as<std::vector<std::pair<qint16,qint16>>>();
        }
    }

...based on input yaml which looks like this...

    myPairs:
      pairOne: [[4, 25], [48, 336]]
      pairTwo: [[4, 25], [57, 336]]
      pairThree: [[4, 25], [48, 336]]

The compiler error output from this is about 300 lines, so I will not post that here. Platform: Visual Studio 2010 SP1 x64

Thanks for your help.

EDIT: Here is the first of many errors I get, namely that it doesn't even seem happy parsing a Node key with the new style... I'm adding this because what is causing this may be related to the other errors.
Code

    YAML::Node doc = YAML::LoadFile(buildFilenamePath(m_spectCameraShortName, relativePath).toStdString());
        if( doc["numPixels"] )
    //...

Causes

    1>ANONPATH\thirdparty\yaml-cpp\include\yaml-cpp/node/detail/impl.h(146): error C2734: 'lhs' : const object must be initialized if not extern
    1>          ANONPATH\thirdparty\yaml-cpp\include\yaml-cpp/node/detail/impl.h(96) : see reference to function template instantiation 'bool YAML::detail::node_data::equals<const char[10]>(YAML::detail::node &,T (&),YAML::detail::shared_memory_holder)' being compiled
    1>          with
    1>          [
    1>              T=const char [10]
    1>          ]
    1>          ANONPATH\thirdparty\yaml-cpp\include\yaml-cpp/node/detail/node_ref.h(52) : see reference to function template instantiation 'YAML::detail::node &YAML::detail::node_data::get<const char[10]>(Key (&),YAML::detail::shared_memory_holder)' being compiled
    1>          with
    1>          [
    1>              Key=const char [10]
    1>          ]
    1>          ANONPATH\thirdparty\yaml-cpp\include\yaml-cpp/node/detail/node.h(103) : see reference to function template instantiation 'YAML::detail::node &YAML::detail::node_ref::get<const char[10]>(Key (&),YAML::detail::shared_memory_holder)' being compiled
    1>          with
    1>          [
    1>              Key=const char [10]
    1>          ]
    1>          ANONPATH\thirdparty\yaml-cpp\include\yaml-cpp/node/impl.h(333) : see reference to function template instantiation 'YAML::detail::node &YAML::detail::node::get<const char[10]>(Key (&),YAML::detail::shared_memory_holder)' being compiled
    1>          with
    1>          [
    1>              Key=const char [10]
    1>          ]
    1>          MYCODEFILE.cpp(75) : see reference to function template instantiation 'YAML::Node YAML::Node::operator []<const char[10]>(Key (&))' being compiled
    1>          with
    1>          [
    1>              Key=const char [10]
    1>          ]

Note that the Line 75 mentioned in the error above is the

    if( doc["numPixels"] ) 

line I've recompiled from source latest using Rev 573 of default branch and all these examples are from that code.


Solution

  • Yes, yaml-cpp should be able to handle nested templates (and so you shouldn't need to define a conversion for std::vector<std::pair<qint16, qint16>> - and, this suggests that yaml-cpp should define a conversion for std::pair<T, U> in general (http://code.google.com/p/yaml-cpp/issues/detail?id=188)).

    And I'm not sure why the compiler doesn't accept your code (it looks correct, and compiles fine on Linux for me).

    Do the tests compile at all? Apparently, 0.5.0 doesn't work out of the box on Visual Studio (see http://code.google.com/p/yaml-cpp/issues/detail?id=182), and I haven't had a chance to test or merge the fix yet.