开发者

Spirit Qi semantic actions and parameters for functions unrelated to the parser

How would I declare a semantic action that calls a free function that doesn't use the attribute the rule/parser returned?

Like, let's say we have a parser that returns a string, but I want to call an unrelated function like Beep, which takes two integer values for frequency and duration and does not care for strings?

Is it actually possible to call it directly, or do I always have to write a proxy function which consumes the string and calls, in this case, Beep in it's body?

Edit: My apologies. I should have mentioned that I used boost::phoenix::bind at first with the syntax Hartmut suggested, which gave me this error:

could not deduce template argument for 'RT (__cdecl *)(T0,T1)' from 'BOOL (__stdcall *)(DWORD,DWORD)'

Is it the calling convention that messes things up here?

Edit2: Seems that's the problem, Hartmuts code compiles with a plain function that takes the same amount and types of arguments as Beep.

example:
bool foo(DWORD a, DWORD b)
{
}

px::bind(&foo,123,456); //comp开发者_如何学编程iles
px::bind(&Beep,123,456); // doesn't compile and generates the error message above.

A google search revealed to me that (most) WINAPI functions use the __stdcall convention, which is not the default convention, __cdecl, which C/C++ functions with the compiler option /Gd use, like in this case: foo

So the answers given so far were all correct, the phoenix solution just didn't work out of the box for me. (Which motivated me to post this question in the first place. I'm sorry for it's undignified and confusing nature, maybe this clears it all up now.)

The only thing unclear to me now is...how I would make phoenix get along with __stdcall, but that should probably be a separate question.


As John said you could use boost::bind. You have to be very careful not to mix and match placeholder variables from different libraries, though. When using boost::bind you need to use its placeholder variables, i.e. ::_1 (yes, boost::bind's placeholders are in global namespace - yuck).

The best solution (and the safest in terms of compatibility) is to utilize boost::phoenix::bind. This is compatible with boost::bind and anything you can do there is possible with phoenix::bind as well (and more). Moreover, Spirit 'understands' Phoenix constructs and exposes all of it's internals using special placeholder variables which are implemented using Phoenix themselves.

In your case the code would look like:

namespace phx = boost::phoenix;
some_parser[phx::bind(&Beep, 123, 456)];

which will call Beep(123, 456) whenever some_parser matches.


I imagine you can use Boost Bind. Instead of writing a wrapper function and giving its address to Qi, you could do this:

boost::bind( Beep, 123, 456 );

This will build a binding which discards its own arguments and calls Beep(123, 456). If you wanted to pass its argument along as well (not that you do here, just to illustrate something common), you can do this:

boost::bind( Beep, 123, 456, _1 );

Then it will call Beep(123, 456, the_string)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜