Re: Using Tuple and bind in Spirit causes compiler error

Larry Evans <[email protected]> Sun, 25 Oct 2020 11:55:55 -0500
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
On 10/23/20 8:49 PM, Joel de Guzman wrote:
> On 10/24/20 1:50 am, Juan Dent wrote:
>> Hi,
>>
>> I produced a MVCE with the error at compile time (see line 22 of
>> MVCE.cpp). REMOVING the semantic action deletes the compiler error!
>> The source is as follows:
>> -------------------------------------------------------------------------------------------------------------------------------------
>>
> 
> If you use clang or g++, this is the error that you will get:
> 
> /usr/local/include/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>,
> ...>'
> 
> Why is that happening? If you are using semantic actions, the semantic
> action **WILL**
> synthesize a suitable attribute for you. In this case, the synthesized
> attribute is
> a boost::fusion::vector which **IS NOT*** assignable to a boost::tuple.
> 
> Suggestion 1: Avoid mixing semantic actions with attributes, unless you
> really know
> what you are doing and already gained more proficiency with Spirit. In
> most cases,
> you can live without semantic actions.
> 
> 
> Suggestion 2: Try other compilers. Error messages generated by Visual
> Studio are
> often tough to decipher.
> 
> Regards,
Suggestion 3: Use transform_attribute:


https://github.com/boostorg/spirit/blob/master/include/boost/spirit/home/qi/action/action.hpp#L57

where the transform_attribute is:

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&) {}
    };
}}}

and where which_attribute is:

enum tag_attribute
{ 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> >;
};

Regards,
Larry