Re: [Boost-users] [Spirit-general] Compile errors with Phoenix closures

Joel de Guzman wrote:
Martin Apel wrote:
Hi all,
I posted this issue a week ago to the Spirit mailing list only, but I got no reply. So I repost this onto the Boost mailing list as well:
I tried to compile a Spirit grammar parsing a real number using closures under Microsoft Visual C++ 2005. The same grammar compiles fine on Linux using GCC 4.x. Boost version is 1.35.0 in both cases. As far as I understood, the error is caused by an assertion inside the closure class template: closure_frame_t& context() { assert(frame!=0); return frame.get(); } (line 352 of boost/spirit/phoenix/closures.hpp)
Even if I define NDEBUG, Phoenix closures don't compile, because the return statement after the assertion returns a pointer to a closure_frame_t and not a reference. From my point of view, this is not really a compiler issue, but a bug in the header file boost/spirit/phoenix/closures.hpp. I do not understand, why GCC compiles this without any errors, because I think the code should not compile at all. Any help would be appreciated.
Please post a minimal cpp file that exhibits the problem. Please try to make it as minimal as possible so as to focus on the problem. At any rate, have you read the FAQ:
http://spirit.sourceforge.net/distrib/spirit_1_8_5/libs/spirit/doc/faq.html#...
Regards,
Hi all, the mentioned FAQ entry is about an assertion triggered at runtime, but I don't even come that far, because the problem happens at compile time. While trying to generate a small example, I found out, what is causing the problem: I marked the grammar class using the closure with __declspec(dllexport), which causes MSVC to instantiate all members of a template, even if they are never needed. It seems that otherwise the "context" member function is never instantiated. If you remove the __declspec(dllexport), everything compiles. I still think, that the code is wrong, because it returns a pointer, where it should return a reference. I have attached a small example, which triggers the problem. By the way, the example implements a real parser, which uses the standard C++ runtime to convert the real number into a double. I had to implement this, because I found out, that the Spirit real_p parser creates numerically different results from the standard runtime, i.e. parsing the string "1.8" delivers a number like 1.8000000532 using Spirit, while the C++ runtime delivers something like 1.7999999973, which is always closer to the real value. Please note, that these numbers are not accurate, they are simply meant to demonstrate, what I mean. Regards, Martin

Martin Apel wrote:
the mentioned FAQ entry is about an assertion triggered at runtime, but I don't even come that far, because the problem happens at compile time.
Ok...
While trying to generate a small example, I found out, what is causing the problem: I marked the grammar class using the closure with __declspec(dllexport), which causes MSVC to instantiate all members of a template, even if they are never needed. It seems that otherwise the "context" member function is never instantiated. If you remove the __declspec(dllexport), everything compiles. I still think, that the code is wrong, because it returns a pointer, where it should return a reference. I have attached a small example, which triggers the problem.
No it is not. You can return a reference to a pointer. Example: char const*& foo() { static char const* s = "hi"; return s; }
By the way, the example implements a real parser, which uses the standard C++ runtime to convert the real number into a double. I had to implement this, because I found out, that the Spirit real_p parser creates numerically different results from the standard runtime, i.e. parsing the string "1.8" delivers a number like 1.8000000532 using Spirit, while the C++ runtime delivers something like 1.7999999973, which is always closer to the real value. Please note, that these numbers are not accurate, they are simply meant to demonstrate, what I mean.
Wow, that's a strong accusation ;-) Again, code please. I can't seem to reproduce your result: parse("1.8", real_p[assign_a(d)]); std::cout.setf(std::ios::fixed|std::ios::left); std::cout.precision(15); std::cout << d << std::endl; gives me: 1.800000000000000 Hmmm... how about: parse("1.800000000000001", real_p[assign_a(d)]; gives me: 1.800000000000001 Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman wrote:
While trying to generate a small example, I found out, what is causing the problem: I marked the grammar class using the closure with __declspec(dllexport), which causes MSVC to instantiate all members of a template, even if they are never needed. It seems that otherwise the "context" member function is never instantiated. If you remove the __declspec(dllexport), everything compiles. I still think, that the code is wrong, because it returns a pointer, where it should return a reference. I have attached a small example, which triggers the problem.
No it is not. You can return a reference to a pointer. Example:
char const*& foo() { static char const* s = "hi"; return s; }
By the way, the example implements a real parser, which uses the standard C++ runtime to convert the real number into a double. I had to implement this, because I found out, that the Spirit real_p parser creates numerically different results from the standard runtime, i.e. parsing the string "1.8" delivers a number like 1.8000000532 using Spirit, while the C++ runtime delivers something like 1.7999999973, which is always closer to the real value. Please note, that these numbers are not accurate, they are simply meant to demonstrate, what I mean.
Wow, that's a strong accusation ;-) Again, code please. I can't seem to reproduce your result:
parse("1.8", real_p[assign_a(d)]); std::cout.setf(std::ios::fixed|std::ios::left); std::cout.precision(15); std::cout << d << std::endl;
gives me:
1.800000000000000
Hmmm... how about:
parse("1.800000000000001", real_p[assign_a(d)];
gives me:
1.800000000000001 Sorry, it wasn't meant as an accusation. I had found this out some months ago, so I tried to give an example from my memory. I didn't expect Spirit to behave exactly as iostream, because there was no specification with respect to numerical accuracy. Additionally I only found this out, when setting the precision to 20, 15 is not enough. I
I know, that you can return a reference to a pointer. But in
boost/spirit/phoenix/closures.hpp closure<..>::context() is declared to
return a reference to a closure_frame_t, which is a closure_frame
participants (2)
-
Joel de Guzman
-
Martin Apel