Posted on March 26th, 2009 at 15:09 by fr3@K
Keiko 寫了篇 討論 DSL 的文字. 這篇文字不短, 有層次. 有他說的 "學院派式" 的格調. 讓我有一種在看一份探討輪胎直徑與胎壓以及胎壁厚度之間關係的 paper 的 feel. 相形之下, 這裡寫的東西看起來更像是黑手示範如何補胎換胎的 howto.
好了, 細節不多談, 建議看官移架拜讀. 重點是, 本要在 comment 裏寫 code, 但這該死的 blogger 超難用, 讓我想起當年 從 blogger 離家出走 的原因.1 又扯遠了, 回到我想回應給 Keiko 的東西.
文字中一段談到 metaprogramming 可以把部份的 domain-specific 錯誤偵測從 run time 往前拉到 compile time. 文中以這樣的 interface 為例:
-
template <int RowT, int ColT>
-
class MyMatrix {
-
public:
-
// !fr3@K! Detail omitted.
-
MyMatrix();
-
};
-
-
// !fr3@K! This explicit declaration is added to help
-
// expressing my point.
-
template <int RowT, int ColT>
-
MyMatrix<RowT, ColT> operator +(
-
const MyMatrix<RowT, ColT>& lhs,
-
const MyMatrix<RowT, ColT>& rhs );
-
MyMatrix<10, 10> m1;
-
MyMatrix<2, 2> m2;
-
-
cout <<m1 + m2 <<endl;
-
template <
-
size_t RowLhs, size_t ColLhs,
-
size_t RowRhs, size_t ColRhs>
-
MyMatrix<RowLhs, ColLhs> operator +(
-
const MyMatrix<RowLhs, ColLhs>& lhs,
-
const MyMatrix<RowRhs, ColRhs>& rhs);
-
template <
-
size_t RowLhs, size_t ColLhs,
-
size_t RowRhs, size_t ColRhs>
-
MyMatrix<RowLhs, ColLhs> operator +(
-
const MyMatrix<RowLhs, ColLhs>& lhs,
-
const MyMatrix<RowRhs, ColRhs>& rhs)
-
{
-
static_assert(
-
RowLhs == RowRhs && ColLhs == ColRhs,
-
"incompatible dimensions");
-
-
MyMatrix<RowLhs, ColLhs> tmp;
-
return tmp += rhs;
-
}
-
template <
-
size_t RowLhs, size_t ColLhs,
-
size_t RowRhs, size_t ColRhs>
-
MyMatrix<RowLhs, ColLhs> operator +(
-
const MyMatrix<RowLhs, ColLhs>& lhs,
-
const MyMatrix<RowRhs, ColRhs>& rhs)
-
{
-
BOOST_STATIC_ASSERT(
-
(RowLhs == RowRhs && ColLhs == ColRhs) &&
-
"incompatible dimensions");
-
-
MyMatrix<RowLhs, ColLhs> tmp;
-
return tmp += rhs;
-
}
-
template <bool> struct my_static_assertion;
-
template <> struct my_static_assertion<true> {};
-
-
#define MY_STATIC_ASSERT(exp, message) \
-
{ \
-
my_static_assertion<((exp) != 0)> ERROR_##message; \
-
(void)ERROR_##message; \
-
}
-
MY_STATIC_ASSERT(
-
RowLhs == RowRhs && ColLhs == ColRhs,
-
incompatible_dimensions);
在這樣的 use case 時:
會產生下面的 compile time error diagnosis (in MSVC 2005):
error C2679: binary '+' : no operator found which takes a right-hand operand of type 'MyMatrix' (or there is no acceptable conversion)
雖然 compiler 已經把錯誤抓到了, 可是錯誤訊息卻不是很友善. Keiko 希望能有 "incompatible dimensions" (domain-specific error) 的提示. Okay, 讓我這個黑手示範一下在這個 use case 下, 怎麼樣叫 compiler 吐出 "incompatible dimensions". operator+ 的宣告要改成類似這樣:
通常, 好的 interface 會儘量設計成不允許錯誤的使用被 compile, 並且讓錯誤發生的時機愈早愈好. Keiko 舉的 use case 所引發的錯誤就是一個例子, 若用 Keiko 的 interface, 這個錯誤會發生在 operator+ 的 caller site, 也就是 Listing 2 的 line 4. 但我為了讓 error message 能更為明確, 選擇反向操作 - 讓 operator+ 的 caller site 能被 compile, 將錯誤 defer 到實例化 operator+ 的時候發生. 其實作為:
我手邊沒有 C++0x 的 compiler, 無法確切告訴你 static_assert 實務上會吐出怎樣的錯誤訊息. 但沒意外的話, 應該會是 Keiko 想要的 message.2
沒有 C++0x 的 compiler? 沒關係, 還有 Boost.StaticAssert:
雖然吐出的 error message 沒有包含 "incompatible dimensions", 但會 output 出包含 "boost::STATIC_ASSERTION_FAILURE" 的訊息, 並指出發生 static assertion failure 的是 line 4 of Listing 2 所 instantiate 的 line 8 of Listing 5. 只要 programmer 跑過去看就可以看到在 BOOST_STATIC_ASSERT 這個 statement 中的 "incompatible dimensions" 字串. 有點麻煩, 有點陽春, but it still works, more or less.
如果你跟我一樣覺得 Boost.StaticAssert 這樣的行為有點鳥, 可以試試另外一種 static assertion 的 implementation, 類似下面這樣:
並把 Listing 5 的第八行開始的 BOOST_STATIC_ASSERT statement 換成:
這時候的 error output 會像下面這樣 (using gcc):
error: ‘ERROR_incompatible_dimensions’ has incomplete type
這個 implementation 有一個很明顯的 limitation, 看 實作 就會知道它要的 message 只能是一個字 (誤). No space, no symbols except underscore (底線/下滑線). 所以在 Listing 7 的例子裏, 用的是 incompatible_dimensions, 而不是更容易讀的 incompatible dimensions.
Have fun!
![]() |
|
| Previous Post « Code Review – ActiveMQ-CPP « |
Next Post » [Note] Installing Review-Board on Ubuntu Linux 8.10 » |
1 Comment »
Except where otherwise noted, COdE fr3@K by
fr3@K is licensed under a
Creative Commons Attribution-Share Alike 3.0 License.
27 queries. 0.546 seconds.
powered by wordpress 2.8.6 | theme by tony








哈哈,這句話太好笑了,中午看到你這句,我就爆笑出來了!
真的很感謝大師的補充,的確,我在寫 domain-specific error checking/report 時,只想到了 C++ 可以用 type system 去做 constraint ,卻忘了 metaprogramming 裡頭的 compiler time assertion 技巧可以補足這部份,看來我還不夠融入 C++ metaprogramming 的思維 : (
或許以後這種討論語言性質的文章,我都應該分兩篇,一篇講 general case ,一篇講 C++ !畢竟 C++ 跟 compiler 是好朋友,很多問題,C++ 都可以拼出好幾組有趣的解法 : ) 好吧,那下一篇文章就是: C++ 在 DSL 的應用了!?
Comment by Keiko — March 26, 2009 @ 22:35