私は QI と Phoenix を使用しており、セマンティック アクション内の関数呼び出しの引数として使用される 4 つの bool を返す小さな文法を書きたいと考えています。
それらを必要とするいくつかの関数があり、これまでのところ、このアプローチを使用しています。
( qi::_bool >> qi::_bool >> qi::_bool >> qi::_bool)
[px::bind(&Bool4Function, spirit::_val, spirit::_1, spirit::_2, spirit::_3, spirit::_4)]
それ自体は問題ありませんが、名前空間の部分を「使用」していても、あちこちで使用するのは見苦しく、混乱を招きます。
そのため、この表現をスタンドアロンの文法に抽出したいと考えました。
だから私はこれを試しました(クレジットはテストベッドのildjarnに行きます):
///// grammar implementation /////
#include <boost/fusion/include/vector10.hpp>
#include <boost/spirit/include/qi_bool.hpp>
#include <boost/spirit/include/qi_char_.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_rule.hpp>
#include <boost/spirit/include/qi_string.hpp>
struct FourBools : boost::spirit::qi::grammar<
char const*,
boost::fusion::vector4<bool, bool, bool, bool>()
>
{
typedef boost::fusion::vector4<bool, bool, bool, bool> attribute_type;
FourBools() : base_type(start_)
{
using boost::spirit::bool_;
start_
= "4bools:"
>> bool_ >> ','
>> bool_ >> ','
>> bool_ >> ','
>> bool_ >> ';'
;
}
private:
boost::spirit::qi::rule<
base_type::iterator_type,
base_type::sig_type
> start_;
};
FourBools const fourBools;
///// demonstration of use /////
#include <string>
#include <ios>
#include <iostream>
#include <boost/fusion/include/at_c.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_parse.hpp>
void noDice(bool a, bool b, bool c, bool d)
{
}
void worksFine(boost::fusion::vector4<bool, bool, bool, bool> a)
{
}
int main()
{
namespace phx = boost::phoenix;
namespace spirit = boost::spirit;
std::string const input("4bools:true,true,true,false;");
char const* first = input.c_str();
char const* const last = first + input.size();
bool const success = spirit::qi::parse(
first, last,
fourBools[phx::bind(&noDice, spirit::_1)]
);
if (!success)
std::cout << "parse() failed\n";
else if (first != last)
std::cout << "didn't consume all input\n";
std::cout.flush();
}
fourBools[phx::bind(&noDice, spirit::_1)]
に置き換えない限り、コンパイルされませんfourBools[phx::bind(&worksFine, spirit::_1)]
。
つまり、私の問題は、引数の数が署名レベルで異なるため、呼び出される関数の署名に一致するように引数をアンパックすることです (4 つのブール値の 1 つのタプルと 4 つのブール値自体)。
タプルを個別の必要がある既存の関数の個々の引数に変換するラッパーを記述する代わりに、フェニックスプレースホルダーを直接使用してアンパックすることは可能ですか? もしそうなら、その構文は何ですか?結局のところ、プレースホルダー( qi::_bool >> qi::_bool >> qi::_bool >> qi::_bool)
によって「アンパック」されると、インライン バージョンは正常に動作します。spirit::_1 - spirit::_4,
そのため、このバージョンもタプルを返すかのように見え、タプルを返す文法とは異なり、上記のアプローチでは何らかの形でアンパック可能です。
どうすればこれに対処できますか?