先に結論を述べます。oven::jointedを使うときには連結元双方のvalue_typeを揃えておきましょう。さもないとおそらく動きません。

それはこういう状況でした。

  • ファイルを1行ずつある処理にかける
  • ただし行の中身によっては次の行へ跨って処理しなければなりない

最終行を読んだ結果、次の行を読まなければならないというときが問題になります。本来はエラーにすべきですが、面倒だったので後ろにダミーの空行を置いて対処することにし、次のようなコードを書きました。

namespace ov = pstade::oven;
std::wistream is(...);
ov::for_each(ov::stream_lines(is) | ov::jointed(ov::single(L"")), process());
//process()は関数オブジェクト

これで良しと思ったのですが、コンパイルしてみると次のような警告となり、無視して実行してみると落っこちます。

pstade\\oven\\./detail/joint_iterator.hpp(156): warning C4172: ローカル変数またはテンポラリのアドレスを返します。
pstade\\oven\\./detail/joint_iterator.hpp(149): クラス テンプレート のメンバ関数 'const string &pstade::oven::detail::joint_iterator<hamigaki::istream_line_iterator<wchar_t,char_traits<wchar_t>,const wchar_t (*)[1]gt;::dereference(void) const' のコンパイル中
VC\\INCLUDE\\xutility(764) : コンパイルされたクラスの テンプレート のインスタンス化 'pstade::oven::detail::joint_iterator<hamigaki::istream_line_iterator<wchar_t,char_traits<wchar_t>,const wchar_t (*)[1]gt;' の参照を確認してください
boost/detail/iter.hpp(83) : コンパイルされたクラスの テンプレート のインスタンス化 'iterator_traits<pstade::oven::detail::joint_iterator<hamigaki::istream_line_iterator<wchar_t,char_traits<wchar_t>,const wchar_t (*)[1]>' の参照を確認してください
boost/iter/iterator_traits.hpp(30) : コンパイルされたクラスの テンプレート のインスタンス化 'boost::detail::iterator_traits<pstade::oven::detail::joint_iterator<hamigaki::istream_line_iterator<wchar_t,char_traits<wchar_t>,const wchar_t (*)[1]>' の参照を確認してください
pstade\\oven\\./iter_range.hpp(169) : コンパイルされたクラスの テンプレート のインスタンス化 'boost::iterator_value<pstade::oven::detail::joint_iterator<hamigaki::istream_line_iterator<wchar_t,char_traits<wchar_t>,const wchar_t (*)[1]>' の参照を確認してください
t.cpp(21) : コンパイルされたクラスの テンプレート のインスタンス化 'pstade::oven::iter_range<pstade::oven::detail::joint_iterator<hamigaki::istream_line_iterator<wchar_t,char_traits<wchar_t>,const wchar_t (*)[1]>' の参照を確認してください

ライブラリのソースを眺めても分かるわけもなく、途方に暮れかけたところで、joint_iteratorのdereference関数がstd::wstring(のconst参照)を返すらしいということに気付きました。試しにov::single(L””)をov::single(std::wstring())にしたら……、動きました。

わかってしまえばなんともないことでした。次のコードで、fはメンバ変数への参照を返すけど、gはstd::wstring型の一時オブジェクトを作ってそれを返そうとしているから駄目という話と同じですね。

class C
{
public:
  std::wstring const& f() {return s;} //OK: sへの参照を返す
  std::wstring const& g() {return p;} //NG: 一時オブジェクトへの参照を返す
private:
  std::wstring s;
  wchar_t const* p; //pは初期化済みとする
};

これ、return文の中の式でも一時オブジェクトをconst参照に結びつけられるというのがミソだったんですね。やれやれです。

スポンサード リンク

この記事のカテゴリ

  • ⇒ oven::jointedの注意