から例外を定義boost::assertion_failed(...)
しBOOST_ENABLE_ASSERT_HANDLER
てスローすることができますboost::optional
。
コード:
#include<boost/exception/to_string.hpp>
namespace boost{
void assertion_failed(char const* expr, char const* function, char const* file, long line){
throw std::runtime_error(std::string()
+ expr +
" from " + function +
" at " + file + ":" + boost::to_string(line)
);
}
}
#define BOOST_ENABLE_ASSERT_HANDLER
#include <boost/optional.hpp>
#undef BOOST_ENABLE_ASSERT_HANDLER
int main(){
double d = *boost::optional<double>{}; // throws! (width fairly useful msg)
(void)d;
}
エラーメッセージ(例外がキャッチされない場合)は次のようになります。
terminate called after throwing an instance of 'std::runtime_error'
what(): this->is_initialized() from reference_type boost::optional<double>::get() [T = double] at /usr/include/boost/optional/optional.hpp:992
その他のリファレンス: http: //boost.2283326.n4.nabble.com/optional-How-to-make-boost-optional-throw-if-trying-to-access-uninitialized-value-td2591333.html
ノート:
assertion_failed
1)一般的に役立つには、のきめ細かい定義が必要になる場合があります。別の種類の例外をスローしたい場合は、関数に条件を設定する以外の方法はわかりませんassertion_failed
(これも私の好みにはハックすぎます):
namespace boost{
void assertion_failed(char const* expr, char const* function, char const* file, long line){
if(std::string("this->is_initialized()") == expr) throw std::domain_error("optional is not intialized");
throw std::runtime_error(std::string()
+ expr +
" from " + function +
" at " + file + ":" + boost::to_string(line)
);
}
}
2)私は他の答えに同意しません、私は1つが行動を選ぶことができるべきだと思います。そして、立ち往生することassert
は良い選択肢ではありません。私の意見では、boost::optional
関数の戻りを含まないコンテキストでの使用があります。
3)std::experimental::optional
バージョンがあります。不思議なことに、彼らは値をとるときにこの問題にとらわれないことに決めました*
(チェックされていない値が返されるため、これは生のポインターの非動作と一致します)が、メンバーは例外.value()
をスローできます。std::experimental::bad_optional_access
これは興味深い設計上の選択です(さらに、2つの方法assert
のいずれも正しいとは思いません)。