LoginSignup
5
2

More than 5 years have passed since last update.

HRESULT型を返されたら例外を投げたいけど短く書きたい。

Posted at

初期状態

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|(略) の左辺が BOOLbool なんかでもコンパイルが通るのが気分悪い。

第四段階 - template を利用して HRESULT 以外をエラーにする

ユーザーコードは第三段階と同じ。

で。
operator|(略) を template にする。
template<typename t> t operator|(t, throwIfFailedClass);
という具合。
で、t が HRESULT 以外の場合にエラーになるように中を書けば良い。

というわけで、第四段階が今のところ最終段階。
HRESULT の正体が long なのでまだ気分悪いんだけど、HRESULT を変えるわけにもいかないので仕方ない。

5
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2