【问题标题】:c++ functional programming ( boost::phoenix && boost::spirit) testing for null-ptrs in pointer placeholdersc++ 函数式编程 ( boost::phoenix && boost::spirit) 测试指针占位符中的 null-ptrs
【发布时间】:2011-06-01 16:38:58
【问题描述】:

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

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 转换为整数(是的,这是错误的,这只是一个实验)。

问题:

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

与所有“C++ 函数式编程库的使用”问题一样,我希望答案会让我感觉自己像个笨蛋。

答案

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

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

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

所以,eps(_r1) 可以解决问题,第二种编译问题与问题无关。

【问题讨论】:

  • 您是否尝试过使用隐式指针到bool 转换? base_rule = eps(_r1)[/*impl*/];
  • (+1) 是的,在static_cast_ 尝试之后,我的大脑抛出了这个问题,可惜它不起作用。如果您想要错误消息,我可以将其添加到我的问题中。
  • 不,我不认为这些错误在这种情况下会有用,只是想在尝试自己编译之前先问一下。 :-]
  • 实际上,鉴于它对我有用,也许这些错误毕竟是有趣的......

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


【解决方案1】:

这是 C++03 中 C++ 类型系统的一个基本问题。 value 0 是特殊的,可以在许多它的 typeint 不能使用的地方使用。这个问题很容易演示,并且在模板和指针结合时会导致很多问题。

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

【讨论】:

  • 最简单的解决方案是停止与文字0 比较,并将指针评估为bool。 ;-]
  • @ildjam。我试过了,它不是运行时 c++ 问题,它(可能)是 phoenix / spirit 构造(或我的理解)的问题。我会尝试将代码隔离成可编译的测试语法。
  • @Hassan :您是否尝试过我回答中的代码?如果它有效,那么这绝对是您的语法特有的问题;如果没有,那么我很困惑。 ;-]
【解决方案2】:

正如我在评论中所建议的那样,使用隐式指向bool 的转换对我来说是开箱即用的 Boost 1.46.1。以下是一个最小的重现,其中parse 在(且仅当)p != 0 &amp;&amp; input == "not null"p == 0 &amp;&amp; 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;
}

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

【讨论】:

  • 你是对的,请参阅我的问题中的 cmets 了解我遇到的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多