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

ゆとりーなの日記

日記的な事を書いて行くと思はれる

思い出したので

今朝閃いたのに家に帰る頃には何書くのかを忘れていたのですが、幸い思い出せたので書いておきます。
まぁネタは以前for_eachで無限ループ書けなくねって話があったので、いやまぁ書こうと思えば書けるのではっていう話です。pstade::oven::iterationが無限リストなるものを作ってくれるらしいのでこれを使います。

#include <iostream>
#include <pstade/oven/algorithm.hpp>
#include <pstade/oven/iteration.hpp>

int main() {
  pstade::oven::for_each(pstade::oven::iteration(0, [](const int x) {return x + 1;}), [](const int x) {
    std::cout << x << std::endl;
  });
  return 0;
}

取り敢えずこれで無限ループになってると思います。数字が無限に出力される筈です。で、一つ気になったのが、条件分岐でループ抜けるときにどうしたらいいんだろうなーっていう話です。まぁ当然breakなんか使えるわけないので困ったものです。取り敢えず思いついたのが、

#include <iostream>
#include <pstade/oven/algorithm.hpp>
#include <pstade/oven/iteration.hpp>

int main() {
  pstade::oven::for_each(pstade::oven::iteration(0, [](const int x) {return x + 1;}), [](const int x) {
    if (x == 129) {
      goto end;
    }
    std::cout << x << std::endl;
  });
end:
  return 0;
}

禁断のgoto文使用だったんですが、これはコンパイルエラーでした。ラムダ式内部から外へは飛べないみたいです。まぁgoto文の仕様を考えるとそんな気もします。setjump系は使うとデストラクタ系統が死亡するので使いたくないのでスルーすると、果たしてどうやって打ち切ればいいのでしょうか。

#include <iostream>
#include <pstade/oven/algorithm.hpp>
#include <pstade/oven/iteration.hpp>
#include <pstade/oven/taken.hpp>

int main() {
  pstade::oven::for_each(pstade::oven::iteration(0, [](const int x) {return x + 1;}) | pstade::oven::taken(129), [](const int x) {
    std::cout << x << std::endl;
  });

  return 0;
}

一応これでループ回数基準の打ち切りは出来ます。しかしループ回数以外の判定で切る時はどうすればいいのかは残念ながら私の頭では分かりませんでした。
追記:
twitterで早速めるぽん先生からtaken_while使えばというコメントをいただいたので早速試したところいけました。

#include <iostream>
#include <pstade/oven/algorithm.hpp>
#include <pstade/oven/iteration.hpp>
#include <pstade/oven/taken_while.hpp>

int main() {
  pstade::oven::for_each(pstade::oven::iteration(0, [](const int x) {return x + 1;}) | 
    pstade::oven::taken_while([](const int x) {return x < 129;}), [](const int x) {
    std::cout << x << std::endl;
  });
  return 0;
}

これを応用すればメッセージループも書けるんではみたいな幻覚に取り憑かれたので、やってみました。

#include <Windows.h>
#include <pstade/oven/algorithm.hpp>
#include <pstade/oven/iteration.hpp>
#include <pstade/oven/taken_while.hpp>
#include <pstade/oven/regular.hpp>

LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp);

int WINAPI WinMain(const HINSTANCE inst, HINSTANCE, LPSTR, const int cmd_show) {
  WNDCLASSEX wc;
  ZeroMemory(&wc, sizeof(WNDCLASSEX));
  wc.cbSize        = sizeof(WNDCLASSEX);
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = WndProc;
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
  wc.lpszClassName = "BASE";
  if (!RegisterClassEx(&wc)) return 0;
  const HWND hWnd = CreateWindow("BASE", "ウィンドウ", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, inst, nullptr);
  if (!hWnd) return 0;
  ShowWindow(hWnd, cmd_show);
  MSG message;
  pstade::oven::for_each(pstade::oven::iteration(0, [](int) {
      return 0;
    }) | 
    pstade::oven::taken_while([&message](int) -> bool {
      if (PeekMessage(&message, nullptr, 0, 0, PM_NOREMOVE)) {
        const BOOL result = GetMessage(&message, nullptr, 0, 0);
        if (!(result && ~result)) {
          return false;
        }
      }
      return true;
    }), 
    [&message](int) {
      TranslateMessage(&message);
      DispatchMessage(&message);
  });
  return message.wParam;
}

LRESULT CALLBACK WndProc(const HWND wnd, const UINT msg, const WPARAM wp, const LPARAM lp) {
  if (msg == WM_DESTROY) {
    PostQuitMessage(0); 
    return 0;
  }
  return DefWindowProc(wnd, msg, wp, lp);
}

非常に誰得なコードが完成しました。因みにpstade::oven::iteration内のラムダ式で変数をキャプチャしたら何故かコンパイルが通らなかったので全てpstade::oven::taken_while内で条件判断を行いました。本当はiteration内の方でPeekMessageしてtaken_whileに戻り値渡してってことをやりたかったんですけど。
どちらかというとドキュメント読めよってかんじでしたね、自分。しかし如何せんovenのドキュメントって英語っていう・・・誰か日本語訳作ってくれませんかねぇ・・・。