Utilizzando la trasformazione eval
che è possibile trovare here come "ispirazione".
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;
}
Perché vuoi farlo? –
Ingannevole. 'stringify (_1 <2);' è _almost_ lo stesso ma ha un'espansione abbastanza diversa. (funzione unaria) – MSalters
Non capisco la domanda. '_1 <_2' definisce una funzione che accetta due argomenti e restituisce un' bool'. Il tuo 'foo' definisce una funzione che prende due argomenti e restituisce' x' o 'y'. Qual è la relazione tra i due? –