Search code examples
c++boostboost-fusionboost-phoenixboost-proto

Displaying a Flattened Phoenix Expression using Boost Fusion


Following the Expressions as Fusion Sequences section of the Proto User Guide, I get to the point where I iterate over a flattened proto expression: _1 + 2 + 3 + 4:

#include <iostream>
#include <boost/phoenix.hpp>

namespace proto   = boost::proto;
namespace fusion  = boost::fusion;
namespace phoenix = boost::phoenix;

struct display
{
  template<typename T>
  void operator()(T const &t) const
  {
    std::cout << t << std::endl;
  }
};

boost::proto::terminal<int>::type const _1 = {1};

int main(int argc, char *argv[])
{
  fusion::for_each(
    fusion::transform(
      proto::flatten(_1 + 2 + 3 + 4)
    , proto::functional::value()
    )
  , display()
  );
  return 0;
}

The _1 placeholder is defined as shown above using proto::terminal. I'd also like to use Boost Phoenix; however, if I instead use the version of _1 defined in boost::phoenix::arg_names in the call to fusion::for_each, I get an error: cannot bind ‘std::ostream {aka std::basic_ostream}’ lvalue to ‘std::basic_ostream&&’. Can I use Phoenix placeholders like this with a Fusion transform?


Solution

  • There is no ostream inserter for phoenix::arg_names::_1. We can easily add one, though. This compiles for me with clang++ (trunk):

    #include <iostream>
    #include <boost/phoenix.hpp>
    
    namespace proto   = boost::proto;
    namespace fusion  = boost::fusion;
    namespace phoenix = boost::phoenix;
    
    struct display
    {
      template<typename T>
      void operator()(T const &t) const
      {
        std::cout << t << std::endl;
      }
    };
    
    namespace boost { namespace phoenix
    {
      template<int N>
      std::ostream& operator<<(std::ostream& sout, argument<N> const& arg)
      {
        return sout << "_" << N;
      }
    }}
    
    int main()
    {
      fusion::for_each(
        fusion::transform(
          proto::flatten(phoenix::arg_names::_1 + 2 + 3 + 4)
        , proto::functional::value()
        )
      , display()
      );
    }