【问题标题】:Can I stringify a Boost Phoenix expression?我可以对 Boost Phoenix 表达式进行字符串化吗?
【发布时间】:2013-03-27 22:05:57
【问题描述】:

我可以将 Boost Phoenix 表达式转换为具有代表性的 C++ 字符串吗?我可以:

stringify(_1<_2);

然后可能会产生一个包含类似以下内容的字符串:

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

我很欣赏这个例子有一些粗糙的地方,但我想知道是否有人尝试过这些方面的东西?

【问题讨论】:

  • 你为什么要这样做?
  • 棘手。 stringify(_1&lt;2); 几乎相同,但扩展方式却大不相同。 (一元函数)
  • 我不明白这个问题。 _1&lt;_2 定义了一个函数,它接受两个参数并返回一个 bool。您的foo 定义了一个函数,该函数接受两个参数并返回xy。两者有什么关系?
  • 糟糕,谢谢埃里克。我会更新“字符串”。
  • 这个例子,就目前而言,假设operator&lt;(T1, T2) 返回bool(模转换序列)。这是相当合理的,但不确定,你可能无法概括这一点。例如。 operator/(T1,T2) 的类型是什么?

标签: c++ templates boost boost-phoenix boost-proto


【解决方案1】:

使用您可以找到here 的转换eval 作为“灵感”。

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;
}

【讨论】:

  • 看起来很有趣,我稍后会运行它。
【解决方案2】:

字符串化是一种预处理器功能 - 您只能对预处理器可用的标记进行字符串化。类型处理(包括类型和表达式扩展)由在预处理器 之后运行的编译器完成,因此您无法执行所需的字符串化。

【讨论】:

  • 我认为您对“stringify”的理解过于字面意思了。我不认为这应该由预处理器完成。毕竟,他并不是要STRINGIFY(_1&lt;_2)——小写字母和小写字母;在说明问题。
  • 除了使用预处理器之外,没有其他方法可以对 C++ 代码进行字符串化:)
  • 对随机 C++ 代码为真,而不是对所有子集。例如,对所有十进制数表达式的子集进行字符串化是很简单的。如果您认为等效代码相等,则更容易,即如果stringify(0x10) 可能产生16
  • 是的,但是 OP 想要获取表达式的类型。除非您为每种可能的类型创建模板特化,否则无法创建可移植的字符串化函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多