Hatena::ブログ(Diary)

C++でゲームプログラミング

2013-03-14

[][][]clang_complete に定義ジャンプの機能が実装されたぽい

最近知ったんですが、clang_complete に定義へジャンプする機能が実装された(されはじめた)ぽいです。

ジャンプしたい名前にカーソルを合わせて <C-]> で定義へと飛ぶことが出来ます。


で、わたしの環境でも軽く試してみたんですが、動作するケースもあれば動作しないケースもあるのでうーん…という感じ。

標準ライブラリが絡むとダメなのかしら。

時間があるときにでももうちょっと調べてみたいですね。


という感じなんですが気になる人は試してみるといいと思います。

ちなみに Windows で使用したい場合は GCC ではなくて Visual Studioビルドしたバイナリを使用する必要があります。

2010-12-15

[][] 各 vec 型に対する次元数の取得方法


関連:クラスに持たせる定数について

http://d.hatena.ne.jp/gintenlabo/20101214/1292329739


現状の個人的なまとめ。

vec 型の次元数を取得するメタ関数 dimension の実装手段をいくつか。

使い方はこんな感じ。

struct my_vec{
    float x, y, z;
};

BOOST_STATIC_ASSERT(( dimension<my_vec>::value == 3 ));
BOOST_STATIC_ASSERT(( dimension<D3DVECTOR>::value == 3 ));

下記のどれかの方法で定義しておけば使うことが出来るとかそんな感じです。

また、dimension の細かい実装方法については割愛。


1.dimension を特殊化

struct my_vec{
    float x, y, z;
};

template<>
struct dimension<my_vec>
    : public boost::integral_constant<std::size_t, 3>{};

template<>
struct dimension<D3DVECTOR>
    : public boost::integral_constant<std::size_t, 3>{};


BOOST_STATIC_ASSERT(( dimension<my_vec>::value == 3 ));
BOOST_STATIC_ASSERT(( dimension<D3DVECTOR>::value == 3 ));

直接 dimension の特殊化を行い、次元数を定義します。

D3DVECTOR の様に外部のライブラリで定義されているものや、変更が出来ない vec 型を使用する場合に有効です。


2.vec 型の内部で定義

struct my_vec{
    typedef boost::integral_constant<std::size_t, 3> dimension_type;
    float x, y, z;
};

template<typename T>
struct dimension : public T::dimension_type{};

BOOST_STATIC_ASSERT(( dimension<my_vec>::value == 3 ));

vec 型の内部で直接定義を行います。

ユーザ側で定義する vec 型には問題ありませんが、D3DVECTOR の様に変更が出来ない vec 型は定義できません。


3.vec_traits を特殊化して定義

struct my_vec{
    float x, y, z;
};

template<typename T>
struct vec_traits;

template<>
struct vec_traits<my_vec>{
    typedef boost::integral_constant<std::size_t, 3> dimension_type;
};

template<>
struct vec_traits<D3DVECTOR>{
    typedef boost::integral_constant<std::size_t, 3> dimension_type;
};

template<typename T>
struct dimension
    : public vec_traits<T>::dimension_type{};


BOOST_STATIC_ASSERT(( dimension<my_vec>::value == 3 ));
BOOST_STATIC_ASSERT(( dimension<D3DVECTOR>::value == 3 ));

vec_traits の特殊化を行い、次元数の定義を行います。

こちらも、dimension の特殊化と同様に、D3DVECTOR の様に定義済みや変更が出来ない vec 型を使用する場合に有効です。

dimension の特殊化と違う点は、次元数以外(例えば、要素の型や iterator 型など)を複数定義する場合に、vec_traits でまとめて定義する事によって、可読性が上がり、変更がしやすいです。

// こんな感じでまとめて定義する
template<>
struct vec_traits<my_vec>{
    typedef boost::integral_constant<std::size_t, 3> dimension_type;
    typedef float* iterator;    // (適当な)iterator 型や
    typedef float value_type;    // 要素の型
};

まとめ

このように各々の定義を行うことで、dimension メタ関数を使用することが出来ます。

複数定義されている場合は、上から順にプラオリティが高くなります。

(2. と 3. が定義されていれば 2. の方が優先して、使用されます)

基本的には、vec_traits で定義し、vec 型の内部で定義されていれば、そちらを優先して使用するって感じになります。

dimension の特殊化は、vec 型の内部で定義されているものを再定義する場合とかかな。

ここでは、次元数の取得を紹介しましたが、要素の型や iterator 型の取得なんかも同じような形で処理を行います。

と、まぁ現状はひとまずこんな感じですね。


以下、チラシの裏


悪魔の所業

長々と書いてきましたが、そんなものいちいち定義するのはめんどくさい!もっと楽がしたい!

と、お思いのあなた!

楽をする方法が 2 つあります。


1つは、『vec 型のサイズ / 要素の型のサイズ』で計算する方法。

template<typename T>
struct dimension
    : public boost::integral_constant<std::size_t, sizeof(T)/sizeof(float)>{};
// ひとまず要素の型 float は決め打ち

struct my_vec{
    float x, y, z;
};

BOOST_STATIC_ASSERT(( dimension<my_vec>::value == 3 ));
BOOST_STATIC_ASSERT(( dimension<D3DVECTOR>::value == 3 ));

おお、素晴らしい。

もちろん、要素の型はどこかで定義しておく必要がありますが、逆にいえば、要素の型があれば次元数を計算することが出来ます。

まぁもちろん、T 型のサイズが『要素型のサイズ x 次元数』である保障はどこにもないのですごく危険ですが。

(vtable があったらその時点でアウト)


2つ目。

もうちょっと頭を柔らかくして考えます。

つまり、T::x, T::y, T::z の変数が定義されていれば3次元、T::x と T::y だけ定義されていれば2次元としてしまえばいいいんじゃないか?と、いう考え。

いや、ある変数が定義されているかどうかなんてコンパイル時に分かるの?って思いますが、C++0x の decltype を使用すれば割と簡単に実装することが出来ます。

(めんどくさいですが C++03 でも出来ないことはないです)

具体的な実装方法は長くなるので割愛しますが、一応、可能かと思います。

まぁこちらも、変数名が違ったり、private だとアクセスできなかったりと問題はいくつかありますが……。


と、そんな感じで、悪魔の所業を2つ考えてみました。

まぁどちらも現状では現実的ではありませんね。

しかし、vec 型ごとに定義しないで済むというのはかなり魅力的。

DirectX の様にかなりの数の vec 型が定義されている場合は使いたくなってきます。

実際にこれらを使って定義するならばもう少し考える必要がありますねー。

以上、終了!

2010-11-07

[][][]ライブラリ構成のメモ書き

以前作成していた vec ライブラリをつくり直す改良するのにしたがって、ライブラリの構成も大幅に変えようと思うので、そのメモ書き。

大まかな作りは、boost や pstade なんか参考にする予定。


覚え書き

  • バージョン管理
  • 使用するのは自分ひとり(予定)
  • テストコードの用意
  • ドキュメントの用意
  • lib や dll は生成しない
  • 将来的に別のライブラリと統合するかも(matrix とか)
  • boost は一部のみ使用する予定(でも、基本的に使わない予定)

目的

  • ライブラリの作成(ライブラリを作る上でも流れを把握)
  • バージョン管理
  • テストコードとドキュメントの作成

ライブラリのコンセプト

多数存在するベクトル型に対し、互換性のある処理を行う為のライブラリ

struct my_vec{
	float x, y, z;
};

my_vec vec;
D3DXVECTOR3 d3dx_vec;

lenght(vec);		// ベクトルの長さを取得
lenght(d3dx_vec);	// 同じ様な形で取得することが出来る

ディレクトリ構成

accelerator\
├―accelerator
│ └―vec     ライブラリのソースコード
└―libs
  └―vec
    ├―doc   ドキュメント
    ├―example 使用例
    └―test   テストコード

テストコード

boost/test/minimal を使用して、テストコードを書く。

1つの *.hpp ファイルに対して、1つのテストコードファイル。

bjam を使って、複数のコンパイラで一気にテストを行う。


ドキュメント

html 形式で用意する予定だが、html でドキュメントを書いた事がないのでなんとも…。

そもそも html を殆ど触ったことがない。

wiki や ブログに書いて、html で出力するとかもありか?

もう少し調べる必要がある。


バージョン管理

バージョン管理は、Git で行う予定。

ただし、本格的に使ったことが無いので手探りになりそう。


ファイルのヘッダー

// accelerator-vec-library
// Copyright (c) 2010 osyo-manga : http://d.hatena.ne.jp/osyo-manga/

boost と pstade 辺りを参考に。

特に意味はないですが形だけでも…。


と、まぁ色々と考えているのですが、考えるだけじゃ先に進まないので、ガシガシソースを書いて行こうと思います。

後から修正なんていくらでも出来るでしょうしね。

そんな訳で何もひとまず何も考えずに書いていくよー。

2010-11-04

[][]ベクトルの要素へのアクセス 〜その5〜

[ベクトル型の例]

boost::array<float, 3>    array_vec;
std::valarray<float>      valarray_vec;

struct my_vec{
    float x, y, z;
};

0.各アクセッサを使用するために最低限必要な実装

x, y, z の要素の型を取得すために vec_value の特殊化を行います。


[使用例]

my_vec vec;

vec_value<my_vec>::type x = vec.x;

vec_value<my_vec>::type
get_x(my_vec& vec){
    return vec.x;
}

[実装例]

template<typename T, std::size_t N>
struct vec_value<boost::array<T, N> >{
    typedef T type;
};

template<typename T>
struct vec_value<std::valarray<T> >{
    typedef T type;
};

template<>
struct vec_value<my_vec>{
    typedef float type;
};

1.イテレータによるアクセス

[使用例]

boost::array<float, 3>    array_vec;
for( vec_iterator<boost::array<float, 3> >::type it = begin(array_vec) ;
     it != end(array_vec) ;
     it++){
    *it = 0;
}

[実装例]

template<typename T, std::size_t N>
struct vec_iterator<boost::array<T, N> >{
    typedef typename boost::array<T, N>::iterator type;
};

template<typename T, std::size_t N>
typename vec_iterator<boost::array<T, N> >::type
begin(boost::array<T, N>& vec){
    return vec.begin();
}

template<typename T, std::size_t N>
typename vec_iterator<boost::array<T, N> >::type
end(boost::array<T, N>& vec){
    return vec.end();
}

[他のアクセス方法]

boost::array<float, 3>    array_vec;

at(array_vec, 0) = get_x(array_vec);
at(array_vec, 1) = get_y(array_vec);
at(array_vec, 2) = get_z(array_vec);

2.インデックスでアクセス

[使用例]

std::valarray<float>    valarray_vec(3);

at(valarray_vec, 0) = 0.0f;
at(valarray_vec, 1) = 0.0f;
at(valarray_vec, 2) = 0.0f;

[実装例]

template<typename T>
T&
at(std::valarray<T>& vec, std::size_t index){
    return vec[index];
}

[他のアクセス方法]

std::valarray<float>    valarray_vec(3);

at(valarray_vec, 0) = 0.0f;
at(valarray_vec, 1) = 0.0f;
at(valarray_vec, 2) = 0.0f;

3.要素へ直接アクセス

[使用例]

my_vec vec;

set_x(vec, 0.0f);
set_y(vec, 0.0f);
set_z(vec, 0.0f);

[実装例]

void
set_x(my_vec& vec, float value){
    vec.x = value;
}
float
get_x(my_vec& vec){
    return vec.x;
}

void
set_y(my_vec& vec, float value){
    vec.y = value;
}
float
get_y(my_vec& vec){
    return vec.y;
}

void
set_z(my_vec& vec, float value){
    vec.z = value;
}
float
get_z(my_vec& vec){
    return vec.z;
}

[他のアクセス方法]

// なし

[][]ベクトルの要素へのアクセス 〜その4〜


まとめ

  • イテレータによるアクセス
    • iterator を使用して、イテレーティブにアクセスを行う
    • インデックスによるアクセスと、要素への直接アクセスも使用できる
  • インデックスでアクセス
    • インデックスを使用して、配列の様にアクセスを行う
    • 要素への直接アクセスも使用できる
  • 要素への直接アクセス
    • 要素へ直接アクセスする
    • 他のアクセス方法は使用できない

イテレータを実装すれば、全てのアクセッサでアクセスすることが出来るとか感じです。

2010-11-03

[][]ベクトルの要素へのアクセス 〜その3〜


#include <boost/iterator_adaptors.hpp>

#include <d3dx9.h>

struct my_vec{
    float x, y, z;
};

//-----------------------------------------------------------------------------

template<typename T>
struct vec_traits;

template<>
struct vec_traits<my_vec>{
    static const int dimension = 3;
    typedef float value_type;
    typedef my_vec vec_type;
    
    struct iterator
        : public boost::iterator_adaptor<
            iterator,
            value_type*,
            value_type&,
            boost::random_access_traversal_tag
        >{
        iterator(vec_traits::value_type* f) : iterator_adaptor_(f){}
    };

    static const value_type& get_x(const vec_type& v){
        return v.x;
    }
    static void set_x(vec_type& v, const value_type& value){
        v.x = value;
    }

    static iterator begin(vec_type& v){
        return iterator(&v.x);
    };
    static iterator end(vec_type& v){
        return iterator( &(v.z) + 1 );
    };
};

template<>
struct vec_traits<D3DVECTOR>{
    static const int dimension = 3;
    typedef float value_type;
    typedef D3DVECTOR vec_type;
    
    struct iterator
        : public boost::iterator_adaptor<
            iterator,
            value_type*,
            value_type&,
            boost::random_access_traversal_tag
        >{
        iterator(vec_traits::value_type* f) : iterator_adaptor_(f){}
    };

    static const value_type& get_x(const vec_type& v){
        return v.x;
    }
    static void set_x(vec_type& v, const value_type& value){
        v.x = value;
    }

    static iterator begin(vec_type& v){
        return iterator(&v.x);
    };
    static iterator end(vec_type& v){
        return iterator( &(v.z) + 1 );
    };
};

template<>
struct vec_traits<D3DXVECTOR3> : public vec_traits<D3DVECTOR>{};

//-----------------------------------------------------------------------------

template<typename T>
struct vec_value_type{
    typedef typename vec_traits<T>::value_type type;
};

template<typename T>
struct vec_dimension{
    static const int value = vec_traits<T>::dimension;
};

template<typename T>
struct vec_iterator{
    typedef typename vec_traits<T>::iterator type;
};

template<typename T>
struct vec_get_x{
    const typename vec_value_type<T>::type&
    operator ()(const T& v){
        return vec_traits<T>::get_x(v);
    }
};

template<typename T>
struct vec_set_x{
    void
    operator ()(T& v, const typename vec_value_type<T>::type& value){
        vec_traits<T>::set_x(v, value);
    }
};

//-----------------------------------------------------------------------------

template<typename T>
const typename vec_value_type<T>::type&
get_x(const T& v){
    return vec_get_x<T>()(v);
}

template<typename T>
void
set_x(T& v, const typename vec_value_type<T>::type& value){
    vec_set_x<T>()(v, value);
}

template<typename T>
typename vec_iterator<T>::type
begin(T& v){
    return vec_traits<T>::begin(v);
}

template<typename T>
typename vec_iterator<T>::type
end(T& v){
    return vec_traits<T>::end(v);
}

template<typename T>
struct vec_range{
    typedef T vec_type;
    typedef typename vec_iterator<T>::type iterator;

    iterator begin(){
        return ::begin(v);
    }
    iterator end(){
        return ::end(v);
    }

    vec_range(vec_type& rhs) : v(rhs){}
private:
    vec_type& v;
};

template<typename T>
vec_range<T>
make_vec_range(T& v){
    return vec_range<T>(v);
}

template<typename T>
typename vec_iterator<T>::type::value_type
at(T& v, std::size_t n){
    return vec_traits<T>::begin(v)[n];
}

//-----------------------------------------------------------------------------

int
main(){
    
    my_vec    vec;
    set_x(vec, 0.0f);
    assert(vec.x == get_x(vec) );
    
    at(vec, 0) = 0.0f;
    at(vec, 1) = 1.0f;
    at(vec, 2) = 2.0f;

    auto range = make_vec_range(vec);
    std::for_each(range.begin(), range.end(),
        [](float value){ std::cout << value << " "; });

    std::valarray<float>    val_vec(3);

    // DirectX
    D3DVECTOR    d3d_vec;
    set_x(d3d_vec, 0.0f);
    assert(d3d_vec.x == get_x(d3d_vec) );
    
    D3DXVECTOR3    d3dx_vec;
    set_x(d3dx_vec, 0.0f);
    assert(d3dx_vec.x == get_x(d3dx_vec) );
    
    return 0;
}

変に考えないで素直に書いてみました。

大元に、 vec_traits があり、各 traits → 各関数につなげて呼び出しを行います。

各 traits で template の特殊化をして実装を行ってもいいし、関数のオーバーロードを使用して実装してもいいので、割と拡張子がしやすいんじゃないかと。

あちこちで実装するのがめんどくさいのであれば、vec_traits にまとめてしまえばいいわけですし。

何はともあれ、最初にあれこれ頭の中で考えるよりも、先に大きい風呂敷を広げて、畳んだ方がいいですね。