読者です 読者をやめる 読者になる 読者になる

ボレロ村上 - ENiyGmaA Code

中3女子です。

qi::int_parser,qi::uint_parser の使いかた

Spirit.Qi には、qi::int_ や qi::uint_ といった、に数値文字列にマッチするプリミティブパーサが用意されている。
これらの Attribute は int や unsigned である。


もし short や unsigned short の Attribute を用いたければ、qi::short_ や qi::ushort_ を使えばよいし、
8進数や16進数をパースしたければ、qi::oct や qi::hex を使えばよい。


さて、では unsigned char 等の Attribute を用いて数値文字列をパースしたいときはどうすればよいだろうか。
残念ながら、qi::schar_ や qi::uchar_ といったプリミティブパーサは用意されていない。


そういった、標準で用意されていないバリエーションの、数値文字列にマッチするパーサを使うには、
qi::int_parser や qi::uint_parser を使えばよい。
なお、これらは Spirit.Qi のドキュメントには記載されていない。
(サンプルコード等にはあるかもしれないが)
※載ってました。
http://www.boost.org/doc/libs/1_46_0/libs/spirit/doc/html/spirit/qi/reference/numeric/int.html
http://www.boost.org/doc/libs/1_46_0/libs/spirit/doc/html/spirit/qi/reference/numeric/uint.html


これが定義されているヘッダは、


である。

// This one is the class that the user can instantiate directly in
// order to create a customized int parser
template <typename T = int, unsigned Radix = 10, unsigned MinDigits = 1
        , int MaxDigits = -1>
struct int_parser;
// This one is the class that the user can instantiate directly in
// order to create a customized int parser
template <typename T = int, unsigned Radix = 10, unsigned MinDigits = 1
        , int MaxDigits = -1>
struct uint_parser;


コメントにあるように、これらは「ユーザーがカスタマイズされた整数型のパーサを作成するために直接インスタンス化できるクラス」である。

    1. T は Attribute の整数型である。
    2. Radix は基数である。
    3. MinDigits は最小の桁数で、MaxDigits は最大の桁数である。


試しにコードを書いてみる。
以下は、カンマ区切りの8bit数値をパースして IPv4 アドレスに格納する。

#include <iostream>
#include <string>
#include <boost/asio/ip/address_v4.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/vector_tie.hpp>

namespace qi = boost::spirit::qi;

int main() {
    typedef boost::asio::ip::address_v4::bytes_type bytes_type;
        // boost::array<unsigned char, 4>
    typedef bytes_type::value_type byte_type;
        // unsigned char
    typedef qi::uint_parser<byte_type> uchar_p;

    std::string input("127,0,0,1");
    bytes_type bytes;

    qi::parse(
        input.begin(),
        input.end(),
        uchar_p() >> ',' >> uchar_p() >> ',' >> uchar_p() >> ',' >> uchar_p(),
        boost::fusion::vector_tie(bytes[0], bytes[1], bytes[2], bytes[3])
        );

    boost::asio::ip::address_v4 ipv4(bytes);

    std::cout << "IPv4 = " << ipv4 << std::endl;
}


なお fusion::vector_tie() は、参照のタプルを作成する。
boost::array は、アダプトすることで Fusion のシーケンスとして扱うこともできるのだが、
この場合はそうしてもコンテナとして解釈され、コンパイルエラーになってしまう。
そのため各要素の参照を fusion::vector に纏めている。


出力は以下のようになる。
(VC9 + Boost 1.46.1)

IPv4 = 127.0.0.1