[C/C++] [template] concept check的簡單實作

posted in: 未分類 | 0

 

可搭配參閱上篇文章: 

[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

Your email address will not be published. Required fields are marked *