Domanda

Can I convert a Boost Phoenix expression into a representative string of C++? I could have:

stringify(_1<_2);

which might then produce a string containing something like:

template <class T1, class T2>
struct foo {
  auto operator()(T1 x1, T2 x2)
  -> decltype(x1 < x2)
  { return    x1 < x2; }
};

I appreciate this example has some rough edges, but I wonder if anything along these lines has been attempted?

È stato utile?

Soluzione

Using the transform eval that you can find here as "inspiration".

Live example.

#include <iostream>
#include <string>
#include <sstream>

#include <boost/phoenix.hpp>
#include <boost/phoenix/core/arity.hpp>
#include <boost/lexical_cast.hpp>

namespace phx=boost::phoenix;
namespace proto=boost::proto;

struct do_print : proto::callable
{
    typedef std::string result_type;

    template <typename NotArgument>
    std::string operator()(NotArgument n)
    {
       return boost::lexical_cast<std::string>(n);
    }

    template <int I>
    std::string operator()(phx::argument<I>)
    {
       return std::string("x")+boost::lexical_cast<std::string>(I-1);
    }

#define UNARY_OP(TAG, OP)                                                       \
    template<typename Arg>                                                      \
    std::string operator()(proto::tag::TAG, Arg arg) const                           \
    {                                                                           \
        return std::string("(") + OP + arg + ")";                                                          \
    }                                                                           \
    /**/

#define BINARY_OP(TAG, OP)                                                      \
    template<typename Left, typename Right>                                     \
    std::string operator()(proto::tag::TAG, Left left, Right right) const            \
    {                                                                           \
        return std::string("(") + left + OP + right + ")";                                                   \
    }                                                                           \
    /**/

    UNARY_OP(negate, "-")
    BINARY_OP(plus, "+")
    BINARY_OP(minus, "-")
    BINARY_OP(multiplies, "*")
    BINARY_OP(divides, "/")
    BINARY_OP(less, "<")
    BINARY_OP(greater, ">")
    /*... others ...*/
};

struct print_expression
  : proto::or_<
        proto::when<proto::terminal<proto::_>, do_print(proto::_value)>
      , proto::otherwise<do_print(proto::tag_of<proto::_>(), print_expression(proto::pack(proto::_))...)>
    >
{};

struct do_get_arity : proto::callable
{
    typedef int result_type;

    template <typename NotArgument>
    int operator()(NotArgument)
    {
       return 0;
    }

    template <int I>
    int operator()(phx::argument<I>)
    {
       return I;
    }


    template<typename Tag, typename Arg>                                                      
    int operator()(Tag, Arg arg) const                           
    {                                                                           
        return arg;                                                         
    }                                                                           
    /**/

    template<typename Tag, typename Left, typename Right>                                    
    int operator()(Tag, Left left, Right right) const           
    {                                                                          
        return std::max(left,right);                                                   \
    }                                                                           

};

struct get_arity
  : proto::or_<
        proto::when<proto::terminal<proto::_>, do_get_arity(proto::_value)>
      , proto::otherwise<do_get_arity(proto::tag_of<proto::_>(),get_arity(proto::pack(proto::_))...)>
    >
{};




template <typename Expr>
std::string stringify(const Expr& expr, const std::string& name="foo")
{
   std::stringstream result;
   int current_arg;
   int arity= get_arity()(expr); 

   result << "template <";

   for(current_arg=0;current_arg<arity-1; ++current_arg)
      result << " typename T" << current_arg << ",";
   result << " typename T" << current_arg;

   result << " >\n";
   result << "struct " << name << " {\n\t";
   result << "auto operator()(";

   for(current_arg=0;current_arg<arity-1; ++current_arg)
      result << " T" << current_arg << " x" << current_arg << ",";
   result << " T" << current_arg << " x" << current_arg;
   result << " )\n\t\t-> typename std::remove_reference< decltype( " << print_expression()(expr) << " ) >::type\n";
   result << "\t{ return " << print_expression()(expr) << "; }\n";
   result << "};\n";

   return result.str();
}

int main()
{
   using phx::placeholders::_1; 
   using phx::placeholders::_2;
   using phx::placeholders::_3;
   std::cout << stringify(-_1) << std::endl;
   std::cout << stringify(_1+_2) << std::endl;
   std::cout << stringify(_1+_2*_3) << std::endl;

   std::cout << stringify((_1+_2)*_3) << std::endl;
   std::cout << stringify(_1>2) << std::endl;
   std::cout << stringify(_1*(-_2)) << std::endl;
   return 0;
}

Altri suggerimenti

Stringification is a preprocessor feature - you can only stringify tokens that are available to the preprocessor. Type handling (including type and expression expansion) is done by the compiler which runs after the preprocessor thus there's no way you could perform the stringification you want.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top