プログラミング言語 Go には defer
という構文があるようです。 私自身は Go を使っていないので感覚としてどの程度便利なものか理解していませんが、 Go の使い手にとってはかなり重要なもののようです。
さて、その defer
を C++ でも使えたらよいのにという意見をツイッタでふと見かけたので、試しにそれらしいものを書いてみました。
defer.h
#ifndef HEADER_7075ab2db3a7279e55c075b6010ee5e0
#define HEADER_7075ab2db3a7279e55c075b6010ee5e0
#include <functional>
#include <type_traits>
#include <utility>
class defer_t {
private:
std::function<void(void)> f;
public:
template<class T, class = typename std::enable_if<std::is_void<decltype((std::declval<T>())())>::value>::type>
defer_t(T const& f) : f(f) {}
~defer_t(void) { f(); }
};
#define defer_helper2(line) defer_tmp ## line
#define defer_helper(line) defer_helper2(line)
#define defer defer_t defer_helper(__LINE__) = [&](void)->void
#endif
以下のような要領で使うことが出来ます。
sample.cpp
#include <iostream>
#include "defer.h"
void test(void) {
defer {
std::cout << "test world" << std::endl;
};
}
void test2(){
defer {
std::cout << "test2 world" << std::endl;
};
}
int main(void) {
defer {
std::cout << "world1" << std::endl;
};
defer {
std::cout << "world2" << std::endl;
};
test();
test2();
std::cout << "world" << std::endl;
return 0;
}
Go では defer
は有用なものでしょうが、 C++ でのより良い設計は後始末をデストラクタに押し込めるべきであり、 defer
のような機能が必要になったとしたらそれは設計がまずいことのサインである可能性が高いです。 しかし、とても残念なことに、設計がまずいライブラリを使わざるを得ないなどということもよくあることで、そのようなときにはこのようなちょっとしたユーティリティが役に立つこともあるかもしれません。