Seasons.NET

ちょっとした技術ブログです

戻り値受け取り型templateクラス

Win32とかMFCつかっていると戻り値でエラーが-1で定義されているものがあり、
そういうときは、

int ret = GetCurSel();
if( ret == (-1) )
{
   /* 失敗した */
}

という鈍くさいコード書かないといけません。
なるべく読み手がわかるように書きたい!!ということで作ってみました。

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

using namespace std;

template < typename T , T failedValueType >
class Result
{
private:
	boost::optional<T> val_;

public:
	Result()
	{
	}
	Result(const T& v) : val_( v )
	{
	}
	operator T()
	{
		return val_.get();
	}
	Result& operator = ( const T& other )
	{
		val_ = other;
		return *this;
	}
	bool is_failed() const
	{
		// val_が未初期化だとboost::optional内のアサートが
		// でるので便利
		return val_.get() == failedValueType;
	}

};

struct Win32Error
{
	enum
	{
		NotCurSel = -1,
	};
};

typedef Result<int,Win32Error::NotCurSel> Win32Result;

int GetCurSel()
{
	return -1; // エラーを返したと仮定して...
}

int _tmain(int argc, _TCHAR* argv[])
{
	Win32Result ret(-1);
	if((ret = GetCurSel()).is_failed())
	{
		std::cout << "失敗しているがな" << std::endl;
	}else
	{
		std::cout << "OKだお" << std::endl;
	}
}


仮に、retで何も受け取らないでおけば、optionalの実装で、get()呼び出し時に、
boost::assertがかかるので便利です。


追記:
id:melponさんからのアドバイス
template Win32Result ThrowIfError(F f)
{
Win32Result r = f(); if (r.is_failed()) throw "エラー";/*なんか例外なげとけーー*/ return r;
}
こんなんできるよ。みたいな。