概念并没有做出的C ++ 0x的标准,但仍升压提供Boost概念检查库(BCCL) 。 我想这BCCL不涵盖,是为了进的C ++ 0x标准的一切。 是什么BCCL和提议的C ++ 0x的解决方案之间的区别?
Answer 1:
检查模板定义
的概念,这些手动解决方案的一个很大的区别是,概念允许模板的定义没有做什么特别的进行类型检查。 概念检查库仅允许使用它是类型检查。 例:
template<typename InputIterator>
int distance(InputIterator a, InputIterator b)
{ return b - a; }
您现在可以撒上概念检查和特质,模板,但写一个模板后,你将永远不会得到一个错误 - 因为标准允许编译器编译推迟模板,直到实例化。 对于检查,你必须写“原型”类,这正好包含了由接口所需的操作,然后实例人为地。
阅读BCCL的文档,我发现它已经包含了像“缺省构造的”共同的原型。 但是,如果你写你自己的概念,你必须也提供自己的原型,这是不容易(你必须要找到确切的最小功能的类型必须提供)。 例如,如果你的原型包含一个operator-
然后用(不正确)的原型模板的测试会成功,虽然这些概念并不需要这样的运营商。
被拒绝的概念的提议为您自动基于上指定和被暗示(指针类型的要求创建原型, T*
在一个参数中使用将暗示为PointeeType要求T
,例如)。 你不必在意这个东西 - 当然除了当你的模板定义包含一个类型的错误。
检查语义需求
考虑以下代码,使用假想概念检查
template<ForwardIterator I>
void f(I a, I b) {
// loop two times!
loopOverAToB(a, b);
loopOverAToB(a, b);
}
该BCCL手册说,语义要求不检查。 只有语法要求和类型进行检查。 考虑一个前向迭代:存在,你可以在多遍算法使用语义要求。 语法检查仅将无法检验这个要求(想想如果流迭代器意外将传递检查会发生什么!)
在被拒绝的建议,你必须明确提出auto
在概念定义前进行语法检查后的编译器标志成功。 如果auto
没有指定是,然后选择一种有明确定义一个概念图说它支持的概念。 甲流迭代器将因此永远不会被带到传递ForwardIterator检查。
语法重映射
这是另一个特点。 模板如
template<InputIterator I>
requires OutputStreamable<I::value_type>
void f(I a, I b) {
while(a != b) std::cout << *a++ << " ";
}
可以使用类似下面,如果用户将提供一个概念图,教编译器如何取消引用一个整数,因此整数如何满足InputIterator的概念。
f(1, 10);
这是一个基于语言的解决方案的好处,并不能由BCCL永远不会得到解决,我相信。
基于概念超载
在BCCL的快速阅读,我也不能当场凡是允许这种情况发生。 一个概念匹配失败似乎导致硬编译错误。 被拒绝的提议允许以下:
template<ForwardIterator I>
I::difference_type distance(I a, I b) {
I::difference_type d = 0; while(a != b) ++a, ++d;
return d;
}
template<RandomAccessIterator I>
I::difference_type distance(I a, I b) {
return b - a;
}
如果一个类型可以有两个模板使用,那么第二个模板将被使用,因为它更专业: RandomAccessIterator
细化ForwardIterator
概念。
Answer 2:
在的C ++ 0x的概念功能将是一个核心的语言特性 ,它的整个过程会被编译器来完成。
Boost概念检查库是几乎相同的功能,但用C ++编写和宏作为一个图书馆 ,模拟了一些功能。 它不能做到这一点会在最后的语言特性(取决于最终的功能定义)要求所有,但为模板类型检查(和其他的编译时检查)的一些等效方案。
至于建议,为的C ++ 0x的概念是一个语言功能,这将允许提供更优雅的语义,让编译器首先使用当前不可用信息的程序,可以让更多详细或智能错误在编译时(如概念目的是为了让模板抽象类型检查)。
Answer 3:
免责声明:我没能即使我升压已经安装的最后30分钟内成功使用BCCL。 你看下面的例子根据升压1.37的BCCL文档看起来不错,但没有奏效。 我想这算作缺点。
随着BCCL你只能得到像静态断言,而语言的核心概念功能提供完整的模块化类型检查,并能防止某些函数模板参与重载决策。 随着本土概念的约束模板的正文可以立即通过编译器,而BCCL不作这方面的编译器检查任何检查。 您必须手动实例化“凯旋门式”参数模板,看看模板使用不可用(例如,operator--对前向迭代器)的任何操作。
至于重载这里是一个例子:
template<typename Iter>
void foo(Iter,Iter) {
BOOST_CONCEPT_ASSERT((RandomAccessIterator<Iter>));
}
void foo(long, int);
int main() {
foo(2,3); // compile-time error
}
模板是更好的匹配,因为非模板需要从int长转换。 但由于int是不是一个迭代器实例化失败。 你得到一个不错的错误消息,说明它,但是这不是非常令人满意的,是吗? 与原生的概念,你可以这样写
template<typename Iter>
requires RandomAccessIterator<Iter>
void foo(Iter,Iter) {}
void foo(long, int);
int main() {
foo(2,3); // OK, picks non-template foo
}
在这里,函数模板不会参与重载决议,因为T = INT的要求没有得到满足。 大!
我们仍然得到约束函数模板与SFINAE伎俩。 的C ++ 0x与decltype和默认模板参数,因为我们可以写函数模板延伸SFINAE及表达,一起
template<typename T> T&& make();
template<typename Iter, class = decltype( *make<Iter>() )>
void foo(Iter,Iter) {}
void foo(long, int);
int main() {
foo(2,3); // OK, picks non-template foo
}
在这种情况下,模板参数推导将静默失败,因为编译器不知道表达的类型*作<Iter项目>()应该是(我们不能解引用一个int)。 带着几分模板元编程和一些宏,我们可以得到相当接近一个可读的方式强加于模板参数任意结构性制约。 下面是它可能是什么样子承担REQUIRES和RandomAccessIterator的适当的定义:
template <typename Iter
REQUIRES( RandomAccessIterator<Iter> )
>
void foo(Iter,Iter) {}
HTH,S