Hatena::ブログ(Diary)

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

2014-07-13

[][]Boost.ScopeExit 使ってみた

そういえば、使ったことがないので試してみた。

Boost.ScopeExit を使用すると『そのスコープを抜けるときの処理』を記述する事ができます。

例えば、スコープの最初の方に『最後に呼ばれる処理』みたいなことを定義する事ができます。


[ソース]

#define BOOST_SCOPE_EXIT_CONFIG_USE_LAMBDAS
#include <boost/scope_exit.hpp>
#include <iostream>

int
main(){
	BOOST_SCOPE_EXIT(void){
		std::cout << "小梅" << std::endl;
	};
	BOOST_SCOPE_EXIT(void){
		std::cout << "幸子" << std::endl;
	};
	std::cout << "ちひろ" << std::endl;
	return 0;
}

[出力]

ちひろ
幸子
小梅

C++11 の場合は BOOST_SCOPE_EXIT_CONFIG_USE_LAMBDAS を定義しておくことで内部でラムダが使用されるようになり、すっきりと書けるようになります。

2014-07-05

[][]C++ で中身が同じ構造体を相互変換する

みたいな話が Lingr の C++ 部屋で出てた。

そういうことを実現したい場合は Boost.Fusion を使うのが現実的かな?

(reinterpret_cast で無理やり変換してしまうという手が無いわけではないのだけれどさすがにアレ過ぎるので。


[ソース]

// 構造が全く同じな型
struct point{
    int x;
    int y;
};


struct vec{
    int x;
    int y;
};


#include <iostream>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/algorithm/auxiliary/copy.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/io.hpp>


// Boost.Fusion にアダプトする
// アダプトすることで任意の型を Boost.Fusion で扱うことができる
BOOST_FUSION_ADAPT_STRUCT(
    point,
    (int, x)
    (int, y)
)

BOOST_FUSION_ADAPT_STRUCT(
    vec,
    (int, x)
    (int, y)
)


int
main(){
    namespace fusion = boost::fusion;
    
    point p{ 1, 2 };
    vec v{ -5, 42 };

    std::cout << fusion::as_vector(p) << std::endl;
    std::cout << fusion::as_vector(v) << std::endl;
    
    // p を v に代入
    fusion::copy(p, v);
    std::cout << fusion::as_vector(p) << std::endl;
    std::cout << fusion::as_vector(v) << std::endl;
    
    return 0;
}

[出力]

(1 2)
(-5 42)
(1 2)
(1 2)

Boost.Fusion にアダプトすることで Boost.Fusion で任意の型を扱えるようにする事ができるのでそれを利用して処理しています。

Boost.Fusion 便利。

ところで fusion::copy() ではなくて operator = を使って代入する方法ってあるのかな。

2014-04-30

[][]Boost.Signals2 で false を返すと disconnect する

と、いうのを書きたかっただけ。


[ソース]

#include <boost/signals2.hpp>
#include <iostream>

template<typename F, typename ...Args>
boost::signals2::connection
connect(boost::signals2::signal<void(Args...)>& sig, F func){
    auto connecter = [=](boost::signals2::connection const& connection, Args... args){
        if( !func(args...) ){
            connection.disconnect();
        }
    };
    return sig.connect_extended(connecter);
}


int
main(){
    boost::signals2::signal<void(int)> sig;
    ::connect(sig, [](int n)->bool{
        std::cout << n << std::endl;
        return true;
    });
    ::connect(sig, [](int n)->bool{
        std::cout << n + n << std::endl;
        return n % 2 != 0;
    });
    ::connect(sig, [](int n)->bool{
        std::cout << n * n << std::endl;
        return n % 3 != 0;
    });
    sig(9);
    sig(8);
    sig(7);

    return 0;
}

[出力]

9
18
81
8
16
7

connect_extended で接続すると 第一引数に boost::signals2::connection が渡されるのでそれを利用すればよいみたい。

書いてから思ったけどこれぐらいならヘルパ関数用意しなくても直接ラムダを書いてしまってもよさそう。

2014-04-26

[][]Ubuntu に boost を入れた

とりあえず、自前で入れるのがちょっとめんどくさかったので apt-get で。


$ sudo apt-get isntall libboost-dev

特にパスを設定する必要もなくこれで boost が使えるように。

ただ、Ubuntu 13.10 だと Boost 1.53 とちょっと古めなので自前で最新版を入れておいたほうがよさそう。

2014-02-15

[][]make_overloaded_function 使ってみた。

前回の記事で『関数の型を書くのがめんどくさい』と書いたら id:RiSK さんから『make_overloaded_function があるよ』とコメントで教えて頂いたので試してみました。



[ソース]

#include <boost/functional/overloaded_function.hpp>
#include <boost/lexical_cast.hpp>
#include <string>
#include <iostream>


std::string
to_string(int n){
    return boost::lexical_cast<std::string>(n);
}

int
to_int(std::string str){
    return boost::lexical_cast<int>(str);
}


int
main(){
    auto multi = boost::make_overloaded_function(&to_string, &to_int);

    std::cout << multi(10) + "-mami" << std::endl;
    std::cout << multi("42") * 2 << std::endl;

    return 0;
}

[出力]

10-mami
84

auto が使用できる環境であればこっちの方がよさそうですね。