LoginSignup
3
1

More than 5 years have passed since last update.

boost::spirit のセマンティックアクションに C++ lambda を使う

Last updated at Posted at 2015-01-25

事の始まり

休日の暇つぶしに boost::spirit のサンプルソースを見ていてセマンティックアクションに
関数ポインタや boost::bind、関数オブジェクトを用いた方法が紹介されていたが、C++11
以降の lambda で代用できるのではという点から。

試行

Parser Semantic Actions

#include<boost/spirit/include/qi.hpp>
#include<string>
#include<iostream>

namespace qi = boost::spirit::qi;

int main(){
  using qi::int_;
  using qi::parse;
  {
    std::string str("{46}");
    auto w = [](int x){std::cout << x << std::endl;};
    parse(
      first,
      last,
      '{' >> int_[w] >> '}'
    );
  }
  return 0; 
}

コンパイルしてみる

環境は gcc 4.9.2 @ msys2 にて。

$ g++ -std=c++11 -o action action.cpp
action.cpp:59:32: error: two consecutive '[' shall only introduce an attribute before '[' token
  parse(first, last, '{' >> int_[ [](int x){std::cout << x << std::endl; } ] >> '}');

いきなり、怒られました。'[[' がいけないのかと思ってスペース挟んだり
もしましたが、駄目な模様。とりあえず下記のように対策

auto w = [](int x){std::cout << x << std::endl;};
parse(
  first,
  last,
  '{' >> int_[w] >> '}'
);
$ g++ -std=c++11 -o action action.cpp
$ ./action
46

どうやら無事動いているようです。ちなみにこのコード、Visual Studio 2013
では正常にコンパイル、実行が出来ました。

Complex

上記のエラーを鑑みて以下のようにコーディング。

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using qi::double_;
using qi::phrase_parse;
using ascii::space;

double rN = 0.0;
double iN = 0.0;
auto cap_real = [&](double x){rN = x; };
auto cap_img = [&](double x){iN = x; };
bool r = phrase_parse(first, last,
           (
             '(' 
             >> double_[cap_real]
             >> -( ',' >> double_[cap_img]) 
             >> ')'
             | double_[cap_real]
           ),
           space);

こちらは問題無くコンパイル及び実行が出来ました。参照キャプチャ
なども問題無く使えるようです。こちらのケースですが、cap_real
のように一度変数に格納してからセマンティックアクションに用いた場合
は問題なかったのですが、double_[[&](double r){...}] のように
した場合、Visual Studio 2013 でもコンパイルエラーが出てしまいました。
template>> みたいな状況になっているのでしょうかね…

まとめ

boost::spirit のセマンティックアクションに c++11 の lambda を使った
ケースを試行してみた。結果、問題無く使えることが判明。
特に Complex では、lambda を用いることで boost::pheonix::ref
boost::spirit::qi::_1 のようなプレースホルダを用いる必要が無くなる
ので using namespace のし忘れなどが減る予感。

Appendix

今回試したソースコードを Gist に置いておきます。
boost_spirit_cpp_lambda.cpp

3
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1