事の始まり
休日の暇つぶしに 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