2017-02-24 13 views
1

私は簡単な一般化されたパーサーコンビネータライブラリを書いています。これは、ライブラリが(と呼ばれる)パーサと呼ばれる多くの小さな関数オブジェクトは、入力として文字列を取り、出力としてParseResultsのリストを返す含むことを意味する、ParseResultはC++:std :: cinの複数のコピーを扱う?

template <typename A> using ParseResult = std::pair<A, std::string> ある場合、パーサーがなかった場合、リストは空です一致しなかった場合は1つの結果が含まれ、複数の(あいまいな)方法で一致する可能性のあるパーサーがさらに結果を返す場合があります。

しかし、これは現在、文字列のコピーが非常に多く行われていることを意味します。また、最初に、最後に構築されたパーサを文字列で呼び出す必要があるため、std::cin(またはファイルのcoompeteの内容)のすべてが文字列にコピーされます。

パーサーは、文字列の最初の部分(最初の(数個)の文字を見ているだけなので)より良いアイデアのようですが、現在の標準入力ストリーム。そして私はこれがまさにstd::istreamであると信じています。ただし、アイスストリームはコピーできません。どのように私の問題を解決することができますか? 原点があるところから数文字先を指しているistreamのコピーを返す方法はありますか?あるいは、この問題を解決するもう一つのきれいな方法がありますか?

+3

C++の参照は何ですか? – PiotrNycz

答えて

1

質問は次のように言い換えることができます。余分なコピーを避け、入力ストリーミングを許す方法で、入力の解析されていない部分をどのように表現しますか?

最も柔軟な方法は、イテレータで表現することです。パーサーがバックトラッキングを行う場合は、ForwardIteratorにする必要があります。そうでない場合は、InputIteratorで十分です。つまり、をstd::cinまたはstd::ifstreamに直接使用するか、またはインメモリstd::stringsまたはcharアレイから解析することができます。バックトラッキングを使用したスト​​リーミングはもう少し複雑で、InputIteratorのようなstd::istream_iteratorForwardIteratorに変換するバッファリング・イテレーター・アダプターを書くか、バックラウンドする必要があるときにstd::ifstreamを直接ラップしてイテレーターを作成して.seekg()と書いてください。

もう1つの選択肢は、コピーしないでいい、解析に適したインターフェイスを持つC++ 17のstd::string_viewです。これでストリーミングは解決されませんが、ファイル全体を最初に読み取る必要があります。

+0

この素晴らしい答えをありがとう!さらなる研究では、 '.seekg()'がstdinに対して正しく動作しないことを指摘しました。つまり、すべてをメモリに読み込むこと(そして、 'std :: istringstream'または' std :: string_view'を使うことは、行く道。 – Qqwy

関連する問題