[C++] C++ で LINQ を実装してみるテスト(前哨戦)

ん~、前哨戦で終了するかもしれませんが、自分の勉強がてら。と、今使っているシステムにできれば組み入れたいので。
将来的に LINQ for C++ ができたとしても、VC++2010 に組み入れられるとは限らないので、やむなく自作ってところでしょうか。実験的なものでなので、拡張性/可読性を考えて導入するかどうかは決めましょう、ということで。

ラムダ式と std::function が使えるようになったから、じゃあ、LINQ らしいメソッドチェーンの方法を試してみたらと思ってざっと書いてみると。

GoingNative 9: LINQ for C/C++, Native Rx, Meet Aaron Lahman | C9::GoingNative | Channel 9
http://channel9.msdn.com/Shows/C9-GoingNative/GoingNative-9-LINQ-for-C-Native-Rx-RxC-Meet-Aaron-Lahman

ああ、確かに上記と同じ方法になります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <tuple>
using namespace std;
 
class Vector : public vector<int> {
protected:
    Vector *_v;
public:
    Vector() :
        _v(NULL) {
    }
    ~Vector() {
        if ( _v != NULL ) {
            delete _v;
        }
    }
    Vector &From( vector<int> &vec ) {
        // アップキャストしてるが、今回はこれで ^^;
        return *(Vector*)&vec;
    }
    Vector &Where(function<bool(int n)> func) {
        // 毎回 new しているが、遅延実行させるため iterator を使う予定
        if ( _v != NULL ) delete _v;
        _v = new Vector;
        for_each( begin(), end(),
            [=](int n) { if(func(n)) _v->push_back(n); });
        return *_v;
    }
    Vector &Select(function<int(int n)> func) {
        if ( _v != NULL ) delete _v;
        _v = new Vector;
        for_each( begin(), end(),
            [=](int n) { _v->push_back(func(n)); });
        return *_v;
    }
};
 
 
int main( void )
{
    Vector vec;
    for ( int i=0; i<10; i++ ) {
        vec.push_back( i );
    }
     
    auto query =
        vec.Where([](int &n)->bool{ return n % 2 == 0 ; })
        .Select([](int &n)->int{ return n*10 ; });
         
    for_each( query.begin(), query.end(),
        [](int n) { cout << n << endl; });
}

肝心の「遅延評価」ができていないので、LINQ とは言えませんが、まあ、表面上はコンパイルが通るし、実行も正常。

1
2
3
4
5
6
D:\work\blog\src\alice>lamda001
0
20
40
60
80

_v = new Vector() してから return *_v で method chain を実現しているんですが、これ memory leak してないか?と思ったのですが、調べるとリークしてませんね。参照で返しているのでブロック外に出ると自動的に解放されています。

元々の vecotr ではなくて、Vector を使わないと駄目なのは、駄目駄目なのでこれはなんとかしないと。
あと遅延評価は C# の IEnumable 相当を作るよりも、iterator をそのまま使いたいんですよね。やっぱり STL と互換性を持たせたいから。

カテゴリー: C++ パーマリンク