Re: Using Tuple and bind in Spirit causes compiler error

Larry Evans <[email protected]> Sun, 25 Oct 2020 13:18:40 -0500
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
On 10/25/20 1:01 PM, Juan Dent wrote:
> Where do I add your code Larry?
> 
> And do I only add this?
> 
I'm sorry Juan, I should have just included the whole code.
Here it is:

//The code:
//The following code was copy&pasted from:
//
https://sourceforge.net/p/spirit/mailman/spirit-general/thread/PH0PR10MB4582B4450F828DD8F663A45E9B1A0%40PH0PR10MB4582.namprd10.prod.outlook.com/#msg37135371
//===========
// MVCE.cpp : This file contains the 'main' function. Program execution
begins and ends there.
//

#include <string>
#include <iostream>

#include <boost/optional/optional_io.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <boost/fusion/container/vector/vector.hpp>
#include <boost/tuple/tuple.hpp>
namespace fusion=boost::fusion;
using fusion::at_c;
using boost::optional;

enum tag_attribute
{ tag_tuple
, tag_vector
};
  std::ostream&
operator<<
  ( std::ostream&sout
  , tag_attribute tag
  )
  {
      return sout<<((tag==tag_tuple)?"tag_tuple":"tag_vector");
  }
template<tag_attribute TagAttribute=tag_vector>
struct which_attribute
{
  using type=fusion::vector<optional<double>, optional<int> >;
};
template<>
struct which_attribute<tag_tuple>
{
  using type=boost::tuple<optional<double>, optional<int> >;
};

#define TRY_USING_BOOST_TUPLE

// #defining this and TRY_USING_ACTION_PRINT creates compile error with
clang10.0.0:
/*
boost/spirit/home/qi/detail/assign_to.hpp:153:20: error: no matching
      conversion for static_cast from 'const
boost::fusion::vector<boost::optional<double>, boost::optional<int> >' to
      'boost::tuples::tuple<boost::optional<double>,
boost::optional<int>, boost::tuples::null_type, boost::tuples::null_type,
      boost::tuples::null_type, boost::tuples::null_type,
boost::tuples::null_type, boost::tuples::null_type,
      boost::tuples::null_type, boost::tuples::null_type>'
            attr = static_cast<Attribute>(val);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
#ifdef TRY_USING_BOOST_TUPLE
tag_attribute constexpr which_tag=tag_tuple;
#include <boost/fusion/tuple.hpp>
#include <boost/fusion/adapted.hpp>
#define TRY_USING_ACTION_TRANSFORM_ATTRIBUTE//Try using the
transform_attribute in action.hpp
  #ifdef TRY_USING_ACTION_TRANSFORM_ATTRIBUTE
namespace boost { namespace spirit { namespace traits
{
    template<>
    struct transform_attribute
    < which_attribute<tag_tuple>::type
    , which_attribute<tag_vector>::type
    , qi::domain
    >
    {
        typedef which_attribute<tag_vector>::type type;
        typedef which_attribute<tag_tuple>::type orig_type;
        static type pre(orig_type& ot)
          {  std::cout<<"transform_attribute::pre\n";
             return type{};
          }
        static void post(orig_type& ot, type& t)
          {  std::cout<<"transform_attribute::post\n";
             at_c<0>(ot)=at_c<0>(t);
             at_c<1>(ot)=at_c<1>(t);
          }
        static void fail(orig_type&) {}
    };
}}}
  #endif//TRY_USING_ACTION_TRANSFORM_ATTRIBUTE
#else
tag_attribute constexpr which_tag=tag_vector;
#endif

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;

using qi::int_;
using qi::double_;
using qi::_1;
using qi::_2;
using ascii::space;

#define TRY_USING_ACTION_PRINT
#ifdef TRY_USING_ACTION_PRINT
void print_pair(boost::optional<double> a, boost::optional<int> b)
{
    if (a)
    {
        auto aa = *a;
        std::cout << aa << std::endl;
    }
    if (b)
    {
        auto bb = *b;
        std::cout << bb << std::endl;
    }
}
#endif//TRY_USING_ACTION_PRINT

bool do_parse()
{
    std::string s = "25 50.77 80";
    std::cout<<"input="<<s<<"\n";
    auto first = s.begin();
    auto last = s.end();
    which_attribute<which_tag>::type to;

    bool r = qi::phrase_parse
        ( first
        , last
        , ( (double_ || int_)
          #ifdef TRY_USING_ACTION_PRINT
            [ phoenix::bind
              ( &print_pair
              , _1
              , _2
              )
            ]
          #endif
          )
        , space
        , to
        );
    auto a = at_c<0>(to);
    auto b = at_c<1>(to);
    std::cout<<"attribute values: a="<<a<<": b="<<b<<"\n";
    if (first == last)
    {
        std::cout<<"parse succeeded!\n";
    }
    else
    {
        std::cout<<"parse failed leaving:"<<std::string{first,last}<<"\n";
    }
    return r;
}

int main()
{
  #if defined(BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT)
    std::cout<<"BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT defined\n";
  #else
    std::cout<<"BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT undef\n";
  #endif
  #if defined(TRY_USING_ACTION_PRINT)
    std::cout<<"TRY_USING_ACTION_PRINT defined\n";
  #else
    std::cout<<"TRY_USING_ACTION_PRINT undef\n";
  #endif
  #if defined(TRY_USING_BOOST_TUPLE)
    std::cout<<"TRY_USING_BOOST_TUPLE defined\n";
  #else
    std::cout<<"TRY_USING_BOOST_TUPLE undef\n";
  #endif
  #if defined(TRY_USING_ACTION_TRANSFORM_ATTRIBUTE)
    std::cout<<"TRY_USING_ACTION_TRANSFORM_ATTRIBUTE defined\n";
  #else
    std::cout<<"TRY_USING_ACTION_TRANSFORM_ATTRIBUTE undef\n";
  #endif
    std::cout<<"which_tag="<<which_tag<<"\n";
    do_parse();
    return 0;
}

//The output:
BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT undef
TRY_USING_ACTION_PRINT defined
TRY_USING_BOOST_TUPLE defined
TRY_USING_ACTION_TRANSFORM_ATTRIBUTE defined
which_tag=tag_tuple
input=25 50.77 80
transform_attribute::pre
25
50
transform_attribute::post
attribute values: a= 25: b= 50
parse failed leaving:.77 80