1

为什么以下Boost.Proto语法不匹配取消引用运算符,正确的方法是什么?

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

namespace proto = boost::proto;
using proto::_;

struct has_deref : proto::or_<
    proto::dereference<_>,
    proto::nary_expr<_, proto::vararg<has_deref>>
    >
{};

template<class Expr>
void test_expr(const Expr &e)
{
    proto::display_expr(e);
    std::cout << "matches? " << std::boolalpha << proto::matches<Expr,
has_deref>::value << std::endl;
}

int main()
{
    test_expr(proto::lit(1) + *proto::lit(2));
}
4

1 回答 1

1

根据您的定义,您的has_deref语法匹配以下表达式:

  • 应用于 ANY 表达式的取消引用运算符
  • 其参数递归匹配语法的任何 n 元(可以是一元如:complementnegateunary_plus二元如:subscriptplus;三元如if_else_或直接 n 元function)表达式。has_deref

在您的示例中,您有一个plus<terminal<int>,dereference<terminal<int> > >类似于binary_expr<tag::plus,terminal<int>,unary_expr<tag::dereference,terminal<int> > >. 当试图匹配你的表达式时(我认为),Proto 首先尝试你的语法的第一个元素(dereference<_>)并且显然失败了。然后尝试第二个并binary_expr<tag::plus,...>匹配nary_expr<_,...>,因此它递归地尝试将语法与plus. 第二个直接匹配,但第一个 ( terminal<int>) 不匹配任何一种可能性,因此整个表达式无法匹配。

一种可能的(可悲的是笨拙的)方法来做你想做的事情可能是这样的:

struct has_deref : proto::or_< //ignoring if_then_else and function
    proto::dereference<_>, 
    proto::unary_expr<_, has_deref>,
    proto::binary_expr<_, has_deref, _>, 
    proto::binary_expr<_, _, has_deref>
    > 
{};

匹配以下任一表达式:

  • 应用于 ANY 表达式的取消引用运算符。
  • 应用于递归匹配的表达式的一元运算符has_deref
  • 一个二元运算符,其第一个操作数是匹配的表达式,has_deref第二个是 ANY 表达式(包括匹配的表达式has_deref)。
  • 二元运算符,其第一个操作数是不匹配的表达式,has_deref第二个是匹配的表达式。

下面是一个检查多个表达式是否与这个新语法匹配的示例(扩展为还检查最多具有 2 个参数的函数):

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

namespace proto = boost::proto; 
using proto::_; 

template <typename Grammar>
struct function_contains_at_least_one : proto::or_<//this is awful, there should be a better way
    proto::function<Grammar>,
    proto::function<Grammar,_>,
    proto::function<_,Grammar>,
    proto::function<Grammar,_,_>,
    proto::function<_,Grammar,_>,
    proto::function<_,_,Grammar>
    >
{};

struct has_deref : proto::or_< //ignoring if_else_
    proto::dereference<_>, 
    proto::unary_expr<_,has_deref>,
    proto::binary_expr<_, _,has_deref>, 
    proto::binary_expr<_,has_deref,_>,
    function_contains_at_least_one<has_deref>
    > 
{}; 

template<class Expr> 
void test_expr(const std::string& repr, const Expr &e) 
{ 
    std::cout << repr << " matches 'has_deref'? " << std::boolalpha << proto::matches<Expr, 
has_deref>::value << std::endl; 
    //display_expr(e);
} 


#define TEST_EXPR( EXPR ) test_expr(#EXPR,EXPR)

int main() 
{ 
    using proto::lit;
    TEST_EXPR(lit(1) + lit(2));
    TEST_EXPR(lit(1) + *lit(2)); 
    TEST_EXPR(*lit(1) + *lit(2));
    TEST_EXPR(*(lit(1) * (lit("foo")+lit(2))));
    TEST_EXPR(+-*lit(1)[~*lit(2)++]);

    //testing functions
    TEST_EXPR( lit(1)() );
    TEST_EXPR( (*lit(1))() );
    TEST_EXPR( lit(1)(lit(2)) );
    TEST_EXPR( (*lit(1))(lit(2)) );
    TEST_EXPR( lit(1)(*lit(2)) );
    TEST_EXPR( lit(1)(lit(2),lit(3)) );
    TEST_EXPR( (*lit(1))(*lit(2),*lit(3)) );
}
于 2016-05-17T16:39:14.337 回答