因為覺得 dprintf 出現的次數實在太多了,我會希望在 exception 就可以包好 __FILE__ 跟 __LINE__,又可以把 std::wstring 包在 exception 一起丟出去,在 catch 的時候再印出來就好。
所以試著寫了這樣一個例子,結果寫的四不像,跟原本想的東西完全部不同了,而且我對於那個 BUFSIZ 相當不滿啊。其實原本希望可以用 ##__VA_ARGS__ 這種 macro 直接吃進來變成一個 boost::any[],然後再想辦法轉成 boost::format 可以用的格式,中間還可以透過 BOOST_FOREACH 來玩的,不過我徹底失敗了,所以最後的成果大家笑笑就好了。
#define BOOST_THROW_EXCEPTION_STRING(fmt, ...)\ do {\ BOOST_THROW_EXCEPTION(an_exception() << throw_wstring(valistToStr(fmt, ##__VA_ARGS__)));\ \ } while(0) inline std::wstring valistToStr(const wchar_t *fmt, ...) { wchar_t wszMessage[BUFSIZ] = {0}; va_list ap; va_start(ap, fmt); vswprintf(wszMessage, sizeof(wszMessage)/sizeof(wszMessage[0]) - 1, fmt, ap); va_end(ap); return std::wstring(wszMessage); } typedef boost::error_info< struct tag_throw_wstring, std::wstring > throw_wstring; struct an_exception : public boost::exception, public std::exception {}; int main(int argc, wchar_t *argv[]) { try { BOOST_THROW_EXCEPTION_STRING( L"%S%d", L"lala", 1); } catch(boost::exception& e) { boost::wformat fmt(L"[%S] %S - [%S(%d)]"); std::wstring wstrError = boost::str(fmt % *boost::get_error_info<boost::throw_function>(e) % boost::get_error_info<throw_wstring>(e)->c_str() % *boost::get_error_info<boost::throw_file>(e) % *boost::get_error_info<boost::throw_line>(e) ); std::wcout << wstrError << std::endl; } return 0; }
然後關於 boost::any 的 construct 不能吃 const char * 的事情,其實不用改到 boost::any 的 source code,稍微這樣惡搞一下就可以了。
class my_any : public boost::any { public: template<typename ValueType> my_any(const ValueType & value) { typename boost::decay<const ValueType>::type t = value; boost::any a(t); this->swap(a); } };
不過我大概要好一段時間碰不到 C++ 了,可能有幾個月要轉換開發平台了(默)
4 responses to “一個 boost::exception 的例子”
我做過類似的事,不知道是不是你要的方法。我的做法不會用到 va_list,也不需要再定一個 wchar_t wszMessage[BUFSIZ].
我是用 function overload template 來做的,像這樣:
template
void BOOST_THROW_EXCEPTION_STRING(const wchar_t *fmt, const T1 &t1)
{ throw exception with a string from (boost::format(fmt) % t1).str() }
template
void BOOST_THROW_EXCEPTION_STRING(const wchar_t *fmt, const T1 &t1, const T2 &t2)
{ throw exception with a string from (boost::format(fmt) % t1 % t2).str() }
從 0 個參數的版本搞到 20 個參數的版本應該就夠用了。
我在這邊的留言也有提到 http://fsfoundry.org/codefreak/2009/05/04/ostream-type-preservation/
ah, 該死,template 的尖角參數又被吃掉了…重貼一次
template<typename T1>
void BOOST_THROW_EXCEPTION_STRING(const wchar_t *fmt, const T1 &t1)
{ throw exception with a string from (boost::format(fmt) % t1).str() }
template<typename T1, T2>
void BOOST_THROW_EXCEPTION_STRING(const wchar_t *fmt, const T1 &t1, const T2 &t2)
{ throw exception with a string from (boost::format(fmt) % t1 % t2).str() }
謝謝你的回覆 😀
其實我也有想到類似的作法,只是當天早上覺得幾個參數就要 overload 幾次,覺得好像跟我的初衷有點不同。不過後來仔細想了想,其實似乎某些 library 也會限制參數的個數來讓可用性更好吧。也許下次我就直接寫寫看好了,比起用 va_list 跟設定一個固定大小的 buffer,我還寧願多 overload 幾次勒 😀
而且多 overload 幾次也不花什麼成本,我看 loki 裡也是一堆這樣用的 XD