可搭配參閱上篇文章:
[insert page=’198′ display=’link’]
concept check導入目的,是為了讓template所產生的編譯錯誤能夠及早在概念層中就被發現,而不是等程式執行到問題發生的那一行才一次性的爆發出template具現化的過程。
例如下面的例子(出自於《C++ Templates全覽》):
#include <iostream> using namespace std; template <typename T> void clear (T p){ *p = 0; // assumes T is a pointer-like type std::cout << p << std::endl; } template <typename T> void core (T const& p){ clear(p); } template <typename T> void middle (typename T::Index p){ core(p); } class Client { public: typedef int Index; }; template <typename T> void shell (T const& env){ typename T::Index i = 10; //std::cout << i << std::endl; middle<T>(i); } Client main_client; int main(){ shell(main_client); system("pause"); }
在進行編譯之後,會產生以下的錯誤訊息:
---- Build started: Project: test, Configuration: Debug Win32 ------ 1>Compiling... 1>main.cpp 1>c:\workspace\test\test\main.cpp(11) : error C2100: illegal indirection 1> c:\workspace\test\test\main.cpp(18) : see reference to function template instantiation 'void clear<T>(T)' being compiled 1> with 1> [ 1> T=Client::Index 1> ] 1> c:\workspace\test\test\main.cpp(26) : see reference to function template instantiation 'void core<Client::Index>(const T &)' being compiled 1> with 1> [ 1> T=Client::Index 1> ] 1> c:\workspace\test\test\main.cpp(46) : see reference to function template instantiation 'void middle<T>(Client::Index)' being compiled 1> with 1> [ 1> T=Client 1> ] 1> c:\workspace\test\test\main.cpp(54) : see reference to function template instantiation 'void shell<Client>(const T &)' being compiled 1> with 1> [ 1> T=Client 1> ] 1>Build log was saved at "file://c:\workspace\test\test\Debug\BuildLog.htm" 1>test - 1 error(s), 0 warning(s) ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
其中 第4行error C2100: illegal indirection所指的便是這段程式所所產生錯誤的原因,會直指向,也就是想做以下的事(試圖將去存取一個reference的pointer,但這卻是錯誤的):
int i = 10; int p = i; *p = 0;
除了第4行之外,5~24行的錯誤都是template具現化的過程,而這些一堆的錯誤訊息其實對我們debug並沒有太大的幫助。(尤其是在複雜一點的系統中,這堆無意義的錯誤常常會讓我們迷失在其中)
因此,如果我們在第一次的function call中就把錯誤指出來的話,便能夠阻止編譯器產生那一堆template的錯誤。
於是concept check的機制由此誕生, 在shell之導入一個用來check的class:
template <typename T> inline void ignore(T) { } template <typename T> void shell (T const& env){ class ShallowChecks { void deref(T::Index ptr) { ignore(*ptr); } }; typename T::Index i = 10; //std::cout << i << std::endl; middle<T>(i); }
之後,錯誤就只剩下一行:
error C2100: illegal indirection
出現在ignore(*ptr);
由於ShallowChecks這個class實際上並不會被用到,因此導入ignore這個dummy function的用意在於壓抑一些會產生警告的編譯器。
最後,boost中有一個Concept Check Library,專門收集一些共通可以用來對template的設計進行check的小程式。就像是本例中位於shell function的local class:ShallowChecks一樣。
Leave a Reply