
本文檔已過期:現在使用的是相似但更新的實現技術。本文檔還引用了本庫的舊接口中的組件和協議,如 BOOST_CLASS_REQUIRES 和 constraints() 函數,它們仍被支持但已反對使用。
我們的最終目標是在模板實例化的位置上捕捉並指出違反概念的錯誤。正如D&E[2]所指出的,可以通過在函數模板上測試所有要求來捕獲錯誤。實際上如何測試要求(特定的有效表達式)是一件微妙的事情,因為我們希望代碼被編譯 --- 但不執行。我們的方法是在一個單獨的函數中測試這些要求,這個函數被賦值給一個函數指針。這種情形下,編譯器將實例化這個函數,但不會真正 調用它。此外,一個優化的編譯器還會將指針賦值作為"死代碼"而刪掉(雖然這個賦值操作在運行期的代價是非常微不足道的)。你可能會想編譯器會不會一開始 就跳過語義分析和約束函數的編譯,從而使我們的函數指針技術不起作用。這是不可能的,由於刪除無用代碼和函數是編譯器最後一步的工作。我們已經在 GNU C++, Microsoft Visual C++, 和多個基於 EDG 的編譯器(KAI C++, SGI MIPSpro)上驗證了函數指針的技術。以下代碼示範了如何把這種技術應用於 std::stable_sort() 函數:
template <class RandomAccessIterator>
void stable_sort_constraints(RandomAccessIterator i)
{
typename std::iterator_traits<RandomAccessIterator>
::difference_type n;
i += n; // 檢查 RandomAccessIterator 的要求
...
}
template <class RandomAccessIterator>
void stable_sort(RandomAccessIterator first, RandomAccessIterator last)
{
typedef void (*fptr_type)(RandomAccessIterator);
fptr_type x = &stable_sort_constraints;
...
}
通常會有一大堆要求需要檢查,對於程序庫的作者來說,為每一個公有函數編寫象 stable_sort_constraints() 一樣的約束函數是一件很煩瑣的事情。為此,我們按照相應的概念的定義,將一組有效表達式集合起來。對於每個概念,定義一個概念檢查類模板,以要檢查的類型作為模板參數。這些類含有一個 contraints() 成員函數,負責測試概念所要求的所有有效表達式。約束函數中使用到的對象,如 n 和 i, 則聲明為概念檢查類的數據成員。
template <class Iter>
struct RandomAccessIteratorConcept
{
void constraints()
{
i += n;
...
}
typename std::iterator_traits<RandomAccessIterator>
::difference_type n;
Iter i;
...
};
我們還可以用這種函數指針機制來引起約束函數的實例化,只不過現在換成了成員函數指針。為了庫更加易於執行概念檢查,我們將成員函數指針機制包裝在一個名為 function_requires() 的函數中。以下代碼片斷示範了如何使用 function_requires() 來確認迭代器是一個 RandomAccessIterator隨機迭代器。
template <class Iter>
void stable_sort(Iter first, Iter last)
{
function_requires< RandomAccessIteratorConcept<Iter> >();
...
}
function_requires() 的定義如下。其中 Concept 為已實例化的概念檢查類。我們將約束成員函數的地址賦值給函數指針 x, 這將引起約束函數的實例化,並檢查概念的有效表達式。然後我們通過將 x 賦值給 x 來避免編譯器的無用變量警告,並將這些都包裝在一個 do-while 循環中以防止名字衝突。
template <class Concept>
void function_requires()
{
void (Concept::*x)() = BOOST_FPTR Concept::constraints;
ignore_unused_variable_warning(x);
}
為了檢查類模板的類型參數,我們提供了 BOOST_CLASS_REQUIRE 宏,它可以用在類定義體內(而 function_requires() 只能用於函數體內)。這個宏聲明了一個嵌套類模板,其模板參數是一個函數指針。我們將這個嵌套類用於一個typedef,並以約束函數的函數指針類型作為模板參數。我們把 type_var 和 concept 的名字用在嵌套類和typedef中,有助於防止名字衝突。
#define BOOST_CLASS_REQUIRE(type_var, ns, concept) \
typedef void (ns::concept <type_var>::* func##type_var##concept)(); \
template <func##type_var##concept _Tp1> \
struct concept_checking_##type_var##concept { }; \
typedef concept_checking_##type_var##concept< \
BOOST_FPTR ns::concept<type_var>::constraints> \
concept_checking_typedef_##type_var##concept
此外,BOOST_CLASS_REQUIRE 還有其它一些版本,帶有更多的參數,以處理那些包含兩個或多個類型相互作用的概念。BOOST_CLASS_REQUIRE 並沒有用於 BCCL 實現的概念檢查中,因為有些編譯器還不能實現以函數指針類型作為模板參數。
Next: Reference 參考
Prev: Programming With
Concepts 用概念編程
| Copyright © 2000 | Jeremy Siek(jsiek@osl.iu.edu) Andrew Lumsdaine(lums@osl.iu.edu), 2007 David Abrahams. |