本文档已过时;目前已使用相似但更新的实现技术。本文档还引用了库旧接口中的组件和协议,例如 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; // exercise the requirements for 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()相反,我们根据相应概念的定义,将一组有效表达式归为一类。对于每个概念,我们定义一个概念检查类模板,其中模板参数是要检查的类型。该类包含一个constraints()成员函数,它执行该概念的所有有效表达式。约束函数中使用的对象,例如nandi,被声明为概念检查类的数据成员。
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()是已经使用建模类型实例化的概念检查类。我们将 constraints 成员函数的地址赋值给函数指针概念,这将导致约束函数的实例化并检查该概念的有效表达式。然后我们赋值x以避免编译器发出未使用的变量警告,并将所有内容包装在 do-while 循环中以防止名称冲突。x到x为了检查类模板的类型参数,我们提供了
template <class Concept>
void function_requires()
{
void (Concept::*x)() = BOOST_FPTR Concept::constraints;
ignore_unused_variable_warning(x);
}
BOOST_CLASS_REQUIRE宏,它可以在类定义的内部使用(而只能在函数体内使用)。此宏声明了一个嵌套类模板,其模板参数是一个函数指针。然后,我们将嵌套类类型用于 typedef,并将约束函数的函数指针类型作为模板参数。我们使用function_requires()type_var名称在嵌套类和 typedef 名称中,以帮助防止名称冲突。and概念此外,还有
#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
的版本宏,它可以在类定义的内部使用(而,它们接受更多参数,以处理包含两个或多个类型之间交互的概念。宏,它可以在类定义的内部使用(而在 BCCL 概念检查的实现中没有使用,因为一些编译器没有实现函数指针类型的模板参数。
| 版权 © 2000 | Jeremy Siek(jsiek@osl.iu.edu) Andrew Lumsdaine(lums@osl.iu.edu), 2007 David Abrahams. |