初期状態
c++
HRESULT hr;
hr=Hoge(略);
if ( FAILED( hr ) ){
throw some_exception(hr);
}
hr=Fuga(略);
if ( FAILED( hr ) ){
throw some_exception(hr);
}
変数が使いまわされている。大変気分が悪い。
第一段階 - 変数の使い回しをやめる。
c++
{
HRESULT hr=Hoge(略);
if ( FAILED( hr ) ){
throw some_exception(hr);
}
}
{
HRESULT hr=Fuga(略);
if ( FAILED( hr ) ){
throw some_exception(hr);
}
}
長くなった。残念すぎる。
第二段階 - 条件節で変数が定義できることを利用する
c++
// CFailed 型を頑張って定義する
if ( CFailed hr = Hoge( 略 ) ){
throw some_exception(hr.get());
}
if ( CFailed hr = Fuga( 略 ) ){
throw some_exception(hr.get());
}
CFailed
型は、
- HRESULT を引数とした 非explicit なコンストラクタがある。
- bool への変換演算子がある
という辺り。
短くなったけど、繰り返しパターンだよねこれ。
第三段階 - 演算子のオーバーロードで一行にまとめる
c++
// throwIfFailed というオブジェクトと、operator|を頑張って定義する
Hoge(略) | throwIfFailed
Fuga(略) | throwIfFailed
-
throwIfFailed
は、throwIfFailedClass
型のオブジェクト。ヘッダでスタティックに定義してしまえば良い。 -
throwIfFailedClass
は、空っぽのクラス。 - あとは
HRESULT operator|(HRESULT, throwIfFailedClass);
があればよい。
なかなかうまく行った。
例外の話が関数よりも後になったので、ソースコードも追いやすい。
すべて inline
にしてしまえば実行時のオーバーヘッドもほぼないだろう。
しかし、operator|(略)
の左辺が BOOL
や bool
なんかでもコンパイルが通るのが気分悪い。
第四段階 - template を利用して HRESULT 以外をエラーにする
ユーザーコードは第三段階と同じ。
で。
operator|(略)
を template にする。
template<typename t> t operator|(t, throwIfFailedClass);
という具合。
で、t
が HRESULT 以外の場合にエラーになるように中を書けば良い。
というわけで、第四段階が今のところ最終段階。
HRESULT の正体が long なのでまだ気分悪いんだけど、HRESULT を変えるわけにもいかないので仕方ない。