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

发布于 2024-11-13 11:00:02 字数 1140 浏览 4 评论 0原文

因此,我有以下精神业力规则主体:

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]

This is valid c++:

struct zebra{};

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

Ithought to try 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) 可以解决问题,第二种编译问题与问题无关。

So, I have the following spirit karma rule body:

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

which leads to a rather long error message from g++ which (helpfully) ends with :

/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]

This is valid c++:

struct zebra{};

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

I thought to try boost::phoenix::static_cast_<_r1_type *>(0) as well as converting _r1_type to a integer (yes that is WRONG, it was just an experiment).

The question:

How can I use a spirit eps construct to perform a pointer test on a placeholder to prevent rule body evaluation when the point is zero ?

As with all "C++ functional programming library usage" questions I expect the answer to leave me feeling like a dimwit.

The Answer

Ildjam's point directly answers my question. There were two issues with my problem; there is a indirect problem above. And that is to do with conditionals in PEG. What I am trying to express should be written as such:

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

I was using the semantic action body ( specified in a [] block), to express the conditional part of the grammar. Strangely though I have written conditional PEG grammars before, I just made a mistake, which led to the second class of problems.

So, eps(_r1) does the trick, The second type of compilation issue is irrelevant to the question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

时光无声 2024-11-20 11:00:02

这是 C++03 中 C++ 类型系统的一个基本问题。 0 很特殊,可以用在许多类型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;
    }
};

This is a fundamental problem with the C++ type system in C++03. The value 0 is special and can be used in many places where it's type, int, cannot. This problem is easily demonstrated and causes plenty of problems where templates and pointers combine.

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.

The simplest solution is to write a quick version of nullptr, which can be found in C++0x.

struct nullptr_t {
    template<typename T> operator T*() const {
        return 0;
    }
};
两相知 2024-11-20 11:00:02

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

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

Using implicit pointer-to-bool conversion, as suggested in my comment, works for me out of the box with Boost 1.46.1. The following is a minimal repro wherein parse succeeds if (and only if) p != 0 && input == "not null" or 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;
}

So, whatever problem you're having while trying to use implicit conversion in this manner, it must be specific to your code; i.e., you'll have to show more of your code to get any useful feedback.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文