可搭配參閱上篇文章:
[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