c ++函数式编程(boost :: phoenix&& boost :: spirit)测试指针占位符中的null-ptrs

时间:2011-06-01 16:38:59

标签: c++ boost boost-spirit boost-phoenix null-pointer

所以,我有以下精神业力规则体:

base_rule = 
    eps(_r1 != 0) [ // _r1 is a pointer_typed placeholder
        eps
    ]
;

导致来自g ++的相当长的错误消息(有用地)以:

结束
/opt/dev_64_swat/Boost/include/boost/spirit/home/phoenix/operator/comparison.hpp
:37:5: error: ISO C++ forbids comparison between pointer and integer 
[-fpermissive]

这是有效的c ++:

struct zebra{};

int main()
{
  zebra * x;
  if( x == 0);  
}

我想尝试boost::phoenix::static_cast_<_r1_type *>(0)以及将_r1_type转换为整数(是的,这是错误的,它只是一个实验)。

问题:

如何使用精神eps构造对占位符执行指针测试,以防止在点为零时进行规则体评估?

与所有&#34; C ++函数式编程库的使用一样&#34;问题我希望答案让我觉得自己像个傻瓜。

答案

Ildjam的观点直接回答了我的问题。我的问题有两个问题;上面有一个间接的问题。这与PEG中的条件有关。我要表达的内容应该是这样写的:

rule = ( eps(_r) << ( /* grammar for when pointer is not null */ ) ) 
    | eps // otherwise dont do anything.
;

我正在使用语义动作主体(在[]块中指定)来表达语法的条件部分。奇怪的是,我之前写过有条件的PEG语法,我只是犯了一个错误,导致了第二类问题。

因此,eps(_r1)可以解决问题,第二种类型的编译问题与问题无关。

2 个答案:

答案 0 :(得分:3)

这是C ++ 03中C ++类型系统的基本问题。 0是特殊的,可以在 type int的许多地方使用,但不能。这个问题很容易证明,并且会导致模板和指针结合的大量问题。

void f(int i) {
    void* ptr = ...;
    if (ptr == i) { // MALFORMED
    }
}

f(0); // But I'm trying to compare with 0, which is legit!

template<typename T, typename Y> T construct_from(const Y& y) {
    return T(y);
}
construct_from<void*>(0); // ERROR, cannot construct ptr from int.

最简单的解决方案是编写nullptr的快速版本,可以在C ++ 0x中找到。

struct nullptr_t {
    template<typename T> operator T*() const {
        return 0;
    }
};

答案 1 :(得分:2)

使用隐式指针到bool转换,正如我的评论中所建议的那样,对我来说,Boost 1.46.1开箱即用。以下是最小的复制品,其中parse成功,如果(仅限于)p != 0 && input == "not null"p == 0 && input == "null"

#include <string>
#include <ios>
#include <ostream>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace spirit = boost::spirit;
namespace qi = spirit::qi;

struct test_grammar : qi::grammar<std::string::const_iterator, void(int*)>
{
    test_grammar() : base_type(start_)
    {
        start_
            =   (   spirit::eps(spirit::_r1)
                    >> "not null"
                |   spirit::eps(!spirit::_r1)
                    >> "null"
                )
                >> spirit::eoi
            ;
    }

private:
    qi::rule<base_type::iterator_type, base_type::sig_type> start_;
};
test_grammar const test;

int main()
{
    int i = 42;
    int* p = &i;                          // alternatively, = 0;
    std::string const input = "not null"; // alternatively, = "null";

    std::string::const_iterator first = input.begin();
    std::cout
        << std::boolalpha
        << "parse succeeded: "
        << qi::parse(first, input.end(), test(p))
        << std::endl;
}

因此,无论您在尝试以这种方式使用隐式转换时遇到什么问题,它都必须特定于您的代码;也就是说,您必须显示更多代码才能获得有用的反馈。