新型scope guard

以前にも何回か書いているスコープガードネタですが(これこれこれ)、http://d.hatena.ne.jp/faith_and_brave/20100921/1285049653 とか http://d.hatena.ne.jp/gintenlabo/20100921/1285084859 から、なんかtwitterで話のネタになってたので、ちゃんとC++0xで使えるカッコイイスコープガード作りましたよ!


#include <iostream>
#include <functional>
#include <utility>

#define PP_CAT(a, b) PP_CAT_I(a, b)
#define PP_CAT_I(a, b) a ## b

template<typename F>
struct scope_exit_t {
scope_exit_t(F & f) : f(f) {}
~scope_exit_t() { std::cout << "by lvalue: "; f(); }
private:
F & f;
};

template<typename F>
struct scope_exit_t<F&&> {
scope_exit_t(F && f) : f(f) {}
~scope_exit_t() { std::cout << "by rvalue: "; f(); }
private:
F f;
};

struct scope_exit_helper {
template<typename F>
scope_exit_t<F&&> operator->*(F && f) const {
return scope_exit_t<F&&>(std::forward<F>(f));
}
};

#define scope_exit_base auto PP_CAT(scope_exit_, __LINE__) = scope_exit_helper() ->*
#define scope_exit scope_exit_base [&] ()
#define scope_exit_2 scope_exit_base

struct fun_obj {
void operator()() { std::cout << "fugafuga\n"; }
};

void f() {
std::cout << "私はカモメ\n";
}

void g(int x) {
std::cout << x << "\n";
}

int main() {
scope_exit { std::cout << "hogehoge\n"; };
scope_exit { std::cout << "piyopiyo\n"; };
scope_exit_2 f;
fun_obj x;
scope_exit_2 x;
scope_exit_2 std::bind(g, 10);
}

scope_exitマクロはラムダ式用、scope_exit_2はそれ以外の関数オブジェクトなどにも使える汎用定義。たいへんいけめんですね。