Семантические действия и параметры Spirit Qi для функций, не связанных с анализатором

#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)