Paepoi

スポンサードリンク
Paepoi » .NET Tips » STL/CLR を使ってみる

STL/CLR を使ってみる

C++/CLI で STL が使えるようなので試してみる。

2011-05-09 関数オブジェクト等を追記

準備

とりあえず新規で「 CLR コンソールアプリケーション 」。
stdafx.h には何も定義されていない、無視すればいい。

その前に DLL パスが私の環境 (Visual Studio 2008 professional) で定義されていなかった。
オプションを開いて

img/stlclr.png

$(ProgramFiles)\Reference Assemblies\Microsoft\Framework\v3.5

を「参照ファイル」に追加。
こうしないと Microsoft.VisualC.STLCLR.dll が参照できません。

とりあえず vector

MSDN を探しても何故かコンテナ関係しか見つからない。
ということで vector で実験してみる。
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
57
58
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <cliext/vector>
 
#using <mscorlib.dll> //コレはネイティブコードを使う時に必要
 
using namespace System;
 
#pragma managed //以下はマネージド
void ManagedFunc()
{
    cliext::vector<String ^> vec;
 
    vec.push_back("あいうえお");
    vec.push_back("かきくけこ");
 
    //iterator は IRandomAccessIterator になる
    cliext::vector<String ^>::iterator ^ it = vec.begin();
    cliext::vector<String ^>::iterator ^ itend = vec.end();
    int i = 0;
 
    for (; it != itend; it->next())
    {
        Console::WriteLine(vec[i++]);
        //Console::WriteLine(it->get_cref()); //こっちのほうが簡単
    }
}
 
#pragma unmanaged //以下ネイティブ
void UnManagedFunc()
{
    std::vector<std::string> vec;
 
    vec.push_back("さしすせそ");
    vec.push_back("たちつてと");
 
    std::vector<std::string>::iterator it = vec.begin();
    std::vector<std::string>::iterator itend = vec.end();
    int i = 0;
 
    for (; it != itend; it++)
    {
        std::cout << vec[i++].c_str() << std::endl;
        //std::cout << it->c_str() < std::endl; //解っているならコレで
    }
}
 
#pragma managed //以下はマネージド
int main(array<System::String ^> ^args)
{
    ManagedFunc();
    UnManagedFunc();
 
    Console::WriteLine("終了するには何かキーを押してください");
    Console::ReadKey();
    return 0;
}


ハンドル型( ^ )がちょっとうっとうしいけどほとんど同じに書ける、これはなかなか。
しかしイテレータは ++ 演算子が定義されているはずなんだがエラーになるので next メソッドで。
とにかくマネージド環境でも同じように使えるというのは嬉しいですね。

普通なテンプレート

とりあえず通常のテンプレートとしては使えるのか?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "stdafx.h"
 
using namespace System;
 
namespace me
{
    // typename が正しいけど class と書いても通る
    template <class T, class T2>
    T2 calc(T a, T2 b)
    {
        return a + b;
    }
}
 
int wmain(int argc, wchar_t* argv[])
{
    Console::WriteLine("20 + 1.5 = {0}", me::calc(20, 1.5));
    //=> 20 + 1.5 = 21.5
    return 0;
}

なるほど問題無いみたい。
template キーワードを generic キーワードに変更するとエラーになる。
generic とは少し違うようだ。
1
2
3
4
5
6
// error
generic <typename T, typename T2>
T2 calc(T a, T2 b)
{
    return a + b;
}

VC++ で T を typename 使うと TCHAR 関連かと少し戸惑ったり...

関数オブジェクト

関数オブジェクトは使えるのだろうか?
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
#include "stdafx.h"
#include <cliext/vector>
#include <cliext/algorithm>
#include <cliext/functional>
 
using namespace System;
using namespace cliext;
 
// 関数オブジェクトテスト
// #include <functional>
template <class T>
ref struct print : public unary_function<T, void>
{
    void operator()(T n)
    {
        Console::Write("{0} ", n * 10);
    }
};
 
ref class Test
{
public:
    Test()
    {
        vector<int> vec;
        for (int i=0; i < 10; i++)
        {
            vec.push_back(i);
        }
        // for_each Test
        // #include <algorithm>
        for_each(vec.begin(), vec.end(), gcnew print<int>());
    }
};
 
int wmain(int argc, wchar_t* argv[])
{
    Test^ t = gcnew Test();
    //=> 0 10 20 30 40 50 60 70 80 90
    return 0;
}
何も問題無い、ref と gcnew キーワードを使う必要があるだけだ。
昔作った STL のコードを流用したい場合にはマジで使えそう。

とも感じるけど Generic の List で同じことをやってみる。
関数オブジェクトを用意する必要が無い。
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
#include "stdafx.h"
 
using namespace System;
using namespace System::Collections::Generic;
 
ref class Test
{
public:
    Test()
    {
        List<int> list ;
        for (int i=0; i < 10; i++)
        {
            list.Add(i);
        }
        for each (int n in list)
        {
            Console::Write("{0} ", n * 10);
        }
    }
};
 
int wmain(int argc, wchar_t* argv[])
{
    Test^ t = gcnew Test();
    //=> 0 10 20 30 40 50 60 70 80 90
    return 0;
}</int>
新たに作るならどう考えたって Generic のほうが簡単だよなぁ...
ついでに Python でもやってみる。
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
 
import sys
 
vector = []
for i in range(10):
    vector.append(i)
for n in vector:
    sys.stdout.write("{0} ".format(n * 10))
    #=> 0 10 20 30 40 50 60 70 80 90
桁違いに簡単...
Copyright(C) sasakima-nao All rights reserved 2002 --- 2025.