#c #boost-spirit-qi
#c #boost-spirit-qi
Вопрос:
Как бы я объявил семантическое действие, вызывающее свободную функцию, которая не использует атрибут, возвращенный правилом / анализатором?
Например, допустим, у нас есть анализатор, который возвращает строку, но я хочу вызвать несвязанную функцию, такую как Beep, которая принимает два целых значения для частоты и длительности и не заботится о строках?
Действительно ли возможно вызвать это напрямую, или мне всегда приходится писать прокси-функцию, которая использует строку и вызывает, в данном случае, Beep в своем теле?
Редактировать: Мои извинения. Я должен был упомянуть, что сначала я использовал boost:: phoenix ::bind с синтаксисом, предложенным Хартмутом, который выдал мне эту ошибку:
could not deduce template argument for 'RT (__cdecl *)(T0,T1)' from 'BOOL (__stdcall *)(DWORD,DWORD)'
Это соглашение о вызовах, которое здесь все портит?
Правка 2: Похоже, в этом проблема, код Хартмута компилируется с простой функцией, которая принимает то же количество и типы аргументов, что и Beep.
example:
bool foo(DWORD a, DWORD b)
{
}
px::bind(amp;foo,123,456); //compiles
px::bind(amp;Beep,123,456); // doesn't compile and generates the error message above.
Поиск в Google показал мне, что (большинство) Функции WINAPI используют соглашение __stdcall, которое не является соглашением по умолчанию, __cdecl, которое используют функции C / C с опцией компилятора / Gd, как в этом случае: foo
Итак, все приведенные до сих пор ответы были правильными, решение phoenix просто не сработало для меня из коробки. (Что побудило меня опубликовать этот вопрос в первую очередь. Прошу прощения за недостойный и сбивающий с толку характер, возможно, теперь это все проясняет.)
Единственное, что мне сейчас неясно, это … как бы я заставил phoenix работать с __stdcall , но это, вероятно, должно быть отдельным вопросом.
Комментарии:
1. Я не понимаю — в чем разница между функцией Beep, о которой вы упоминали изначально, и новой «простой функцией, которая принимает те же аргументы, что и Beep»?
2. Ну, я все еще новичок, поэтому мой ответ, скорее всего, будет нетехническим или даже неправильным, но поскольку «bool foo (DWORD, DWORD)» соответствует, а Beep — нет, мне кажется, что foo может быть скомпилирован с другим соглашением о вызовах, но, как я уже сказал, я новичок, так что для меня это может быть волшебством. Один просто работает, другой нет, и все, что я сделал, это обменял функции, на которые указаны, оставив остальной синтаксис таким, как было предложено.
3. О, я понимаю, проблема в соглашении о вызовах! Это задокументировано здесь: beta.boost.org/doc/libs/1_46_1/libs/bind/bind.html#stdcall
Ответ №1:
Как сказал Джон, вы могли бы использовать boost::bind
. Однако вы должны быть очень осторожны, чтобы не смешивать переменные-заполнители из разных библиотек. При использовании boost::bind
вам нужно использовать его переменные-заполнители, т.Е. ::_1
(да, заполнители boost::bind находятся в глобальном пространстве имен — фу).
Лучшим решением (и самым безопасным с точки зрения совместимости) является использование boost::phoenix::bind
. Это совместимо с boost::bind
, и все, что вы можете там сделать, также возможно с phoenix::bind
(и не только). Более того, Spirit «понимает» конструкции Phoenix и предоставляет доступ ко всем его внутренним компонентам, используя специальные переменные-заполнители, которые реализованы с использованием самих Phoenix.
В вашем случае код будет выглядеть следующим образом:
namespace phx = boost::phoenix;
some_parser[phx::bind(amp;Beep, 123, 456)];
который будет вызываться Beep(123, 456)
всякий some_parser
раз, когда совпадет.
Комментарии:
1. Это была моя самая первая попытка, поскольку я нахожусь в процессе более тесного взаимодействия с анализаторами, которые фактически выполняют некоторую обработку, а не просто заполняют структуры внешним этапом постпроцесса, приношу свои извинения за то, что опустил эту часть.
Ответ №2:
Я полагаю, вы можете использовать Boost Bind. Вместо того, чтобы писать функцию-оболочку и передавать ее адрес Qi, вы могли бы сделать это:
boost::bind( Beep, 123, 456 );
Это создаст привязку, которая отбрасывает свои собственные аргументы и вызовы Beep(123, 456)
. Если вы хотите также передать его аргумент (здесь вы этого не делаете, просто для иллюстрации чего-то общего), вы можете сделать это:
boost::bind( Beep, 123, 456, _1 );
Затем он вызовет Beep(123, 456, the_string)