Hatena::ブログ(Diary)

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

2013-03-10

[][]PStade.Oven hetero

昨日の記事のコメントで教えて頂いたので覚書。

PStade.Oven に tuple から任意の型の range へと変換する関数が用意されているらしいので使ってみた。


[ソース]

#include <pstade/oven/hetero.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/any.hpp>
#include <iostream>
#include <string>


struct shape{
	virtual void draw() = 0;
};

struct rectangle : shape{
	virtual void draw(){
		std::cout << "rectangle" << std::endl;
	}
};

struct triangle : rectangle{
	virtual void draw(){
		std::cout << "triangle" << std::endl;
	}
};

struct circle : rectangle{
	virtual void draw(){
		std::cout << "circle" << std::endl;
	}
};


int
main(){
	namespace oven = pstade::oven;

	rectangle r; triangle t; circle c;
	boost::tuple<rectangle*, triangle*, circle*> tup(&r, &t, &c);
	for(shape* s : oven::hetero<shape*>(tup)){
		s->draw();
	}


	auto tup2 = boost::make_tuple(42, std::string("homu"), 3.14f, std::string("mado"));
	auto any_range = oven::hetero<boost::any>(tup2);
	std::cout << boost::any_cast<int>(any_range[0]) << std::endl;
	std::cout << boost::any_cast<std::string>(any_range[1]) << std::endl;
	std::cout << boost::any_cast<float>(any_range[2]) << std::endl;
	std::cout << boost::any_cast<std::string>(any_range[3]) << std::endl;

	return 0;
}

[出力]

rectangle
triangle
circle
42
homu
3.14
mado

なかなかよさげですね。

しかし、なんでもあるな PStade.Oven。


[参照]

http://p-stade.sourceforge.net/oven/doc/html/oven/ranges.html#oven.ranges.hetero

2013-01-12

[][][]pstade::oven::outdirected の実装と Boost.Range でエミュレート

pstade::oven::outdirected の実装がどうなっているのかなーとソースコードを見てみたら pstade::oven::counting でラップしているだけでした。

こんな感じ。


std::vector<int> v = {1, 2, 3, 4, 5};

auto outdirect = pstade::oven::counting(std::begin(v), std::end(v));

boost::for_each(outdirect, [](std::vector<int>::iterator it){
    std::cout << *it << std::endl;
});

ほむほむ、なるほどなー。

で、同等の機能を Boost.Range で実装する場合は boost::irange を使えばよさそう。


[ソース]

#include <boost/range/irange.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <iostream>

template<typename Range>
auto
outdirect(Range& range)
->decltype(boost::irange(std::begin(range), std::end(range))){
    return boost::irange(std::begin(range), std::end(range));
}


int
main(){
    std::vector<int> v = {1, 2, 3, 4, 5};

    boost::for_each(outdirect(v), [](std::vector<int>::iterator it){
        std::cout << *it << std::endl;
    });

    return 0;
}

[出力]

1
2
3
4
5

[boost]

  • ver 1.52.0

2013-01-11

[][][]algorithm のコールバック関数iterator を受け取りたかった

for_each や find_if 等を使う時に、値ではなくて iterator として関数で受け取りたい場合があったのでちょっと調べてみました。

要は Boost.Range にある indirected の逆。

Boost.Range には見当たらなかったんですが PStade.Oven の <pstade/oven/outdirected.hpp> を使えばいいみた。


[ソース]

#include <pstade/oven/outdirected.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <iostream>

int
main(){
    using boost::lambda::_1;
    using pstade::oven::outdirected;

    std::vector<int> v = {1, 2, 3, 4, 5};

    boost::for_each(v | outdirected, [](std::vector<int>::iterator it){
        std::cout << *it << std::endl;
    });

    return 0;
}

[出力]

1
2
3
4
5

答えを見つけるまでにだいぶ時間をかけてしまった…。

2010-10-22

[][]pstade::oven::single(x)


#include <iostream>
#include <string>

#include <pstade/oven/single.hpp>
#include <pstade/oven/io.hpp>
#include <pstade/oven/transformed.hpp>

int
main(){
    namespace oven = pstade::oven;

    boost::equal(oven::single('F'), std::string("F"));
    std::cout << oven::single(10) << std::endl;
    
    // 1次元配列を2次元っぽく
    int array[] = {0, 1, 2, 3, 4};
    std::cout << (array|oven::transformed(oven::single)) << std::endl;
    
    return 0;
}

[出力]

{10}
{{0},{1},{2},{3},{4}}

pstade::oven::single(x) は、x を range にして返します。

中身は、

begin(&x), end(&x+1)

の様な形の range にしています。

pstade::oven::transformed に渡すと 2次元配列っぽく変換できますね。


[pstade]

ver 1.04.3

[][]pstade::oven::dropped(n)


#include <iostream>
#include <string>

#include <pstade/oven/dropped.hpp>
#include <pstade/oven/io.hpp>


int
main(){
    namespace oven = pstade::oven;

    int array[] = {0, 1, 2, 3, 4, 5, 6, 7};

    std::cout << (array|oven::dropped(3)) << std::endl;
    
    return 0;
}

[出力]

{3,4,5,6,7}

pstade::oven::dropped(n) は、range の先頭から n 個分の要素を取り除いた range を返すアダプタです。

先頭からどんどん切り捨てて使うようなデータ(ファイルデータとか?)に便利そうですね。


[pstade]

ver 1.04.3

2010-10-21

[][]pstade::oven::offset(n, m)


#include <iostream>

#include <pstade/oven/offset.hpp>
#include <pstade/oven/io.hpp>

int
main(){
    namespace oven = pstade::oven;

    int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    std::cout << (array|oven::offset(2, -1)) << std::endl;

    return 0;
}

[出力]

{2,3,4,5,6,7,8}

pstade::oven::offset(n, m) は、

begin(range)+n, end(range)+m

の範囲を返すアダプタです。

pstade::oven::window との違いは、begin() と end() を基準にしているところです。


[pstade]

ver 1.04.3

[][]pstade::oven::window(n, m)


#include <iostream>

#include <pstade/oven/window.hpp>
#include <pstade/oven/io.hpp>

int
main(){
    namespace oven = pstade::oven;

    int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    std::cout << (array|oven::window(1, 7)) << std::endl;

    return 0;
}

[出力]

{0,1,2,3,4,5}

pstade::oven::window(n, m) は、

begin(range)+n, begin(range)+m

の範囲を返すアダプタです。

pstade::oven::offset との違いは、両方共 begin() を基準にしているところです。


[pstade]

ver 1.04.3