
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; }
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<self_t>. The implementation consists of frame.get(), which invokes the get method on holder_t, which is a closure_frame_holder<closure_frame_t>. When looking at the get method of closure_frame_holder, it returns a reference to frame_ptr, which is a frame_t*, which is not the same as an object of type closure_frame<self_t> as declared by closure<...>::context()
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 played around a bit, to find an example: #include <string> #include <sstream> #include <iostream> #include <boost/spirit/core.hpp> #include <boost/spirit/actor.hpp>
int main(void) { using namespace std; using namespace boost::spirit; double d; string s("0.6"); parse(s.begin(), s.end(), real_p[assign_a(d)]); cout.setf(std::ios::fixed|std::ios::left); cout.precision(20); cout << "Parsing with Spirit gives: " << d << endl; stringstream stream(s); double std_result; stream >> std_result; std::cout << "Parsing with iostream gives: " << std_result << endl; } results in the following in my machine: Parsing with Spirit gives: 0.60000000000000008882 Parsing with iostream gives: 0.59999999999999997780 Hope this helps, Regards, Martin