【问题标题】:What's the difference between C++0x concepts and The Boost Concept Check Library (BCCL)?C++0x 概念和 Boost 概念检查库 (BCCL) 有什么区别?
【发布时间】:2009-08-29 22:44:41
【问题描述】:

Concepts 没有使 C++0x 成为标准,但 Boost 仍然提供 The Boost Concept Check Library (BCCL)。我猜 BCCL 并没有涵盖 C++0x 标准中的所有内容。 BCCL 和提议的 C++0x 解决方案有什么区别?

【问题讨论】:

  • 自从提出这个问题以来,概念已从 c++0x 标准中删除。来源:drdobbs.com/visualstudio/227500449
  • @red:这就是前 6 个单词中已经提到的问题。
  • 噢!阅读主题,而不是正文。抱歉打扰了。

标签: c++ boost c++11 c++-concepts


【解决方案1】:

检查模板定义

这些手动解决方案的概念的一个很大区别是概念允许对模板的定义进行类型检查,而无需做任何特殊的事情。概念检查库只允许对它的 *use* 进行类型检查(除非您手动编写测试实例化类型或为标准情况使用提供的类型,见下文)。例子:
template<typename InputIterator>
int distance(InputIterator a, InputIterator b) 
{ return b - a; }

您现在可以在该模板中添加概念检查和特征,但在编写该模板后您将永远不会出错 - 因为标准允许编译器延迟编译模板直到实例化。为了检查,您必须编写“原型”类,其中包含接口所需的操作,然后人工实例化它们。

阅读 BCCL 的文档后,我发现它已经包含了常见的原型,例如“默认可构造”。但是,如果您编写自己的概念,则还必须提供自己的原型,这并不容易(您必须准确找到类型必须提供的最小功能)。例如,如果您的原型包含 operator-,那么使用该(不正确的)原型测试您的模板将会成功,尽管这些概念不需要这样的运算符。

被拒绝的概念提案会根据指定和隐含的要求自动为您创建原型(例如,参数中使用的指针类型 T* 将暗示 T 的 PointeeType 要求)。您不必关心这些东西 - 当然,除非您的模板定义包含类型错误。

检查语义要求

考虑这段代码,使用假设的概念检查

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 概念。

【讨论】:

  • 很好的答案,但这里的开场白是错误的,文章继续自相矛盾。
  • @dave 我很高兴知道我错在哪里,这样我就可以修正我的答案并学习一些东西。
  • 我的观点是,概念检查库确实允许对定义进行类型检查(与开场白相反),您的文章甚至继续指出这一事实。
  • @dave 好的,我明白了。如果我有时间,我会调整措辞。
【解决方案2】:

C++0x 概念特性将是一个核心语言特性,其整个过程将由编译器完成。

Boost 概念检查库是几乎相同的功能,但用 C++ 和宏作为库编写来模拟一些功能。它不能完成最终语言功能(取决于最终功能定义)所需的所有功能,但为模板类型检查(和其他编译时检查)提供了一些等效的解决方案。

正如建议的那样,由于 C++0x 概念是一种语言特性,它将允许提供更优雅的语义并允许编译器使用程序当前不可用的信息,从而允许在编译时出现更详细或更智能的错误(如概念的第一个目的是允许模板中的抽象类型检查)。

【讨论】:

    【解决方案3】:

    免责声明:即使我已经安装了 Boost,我也无法在过去 30 分钟内成功使用 BCCL。根据 Boost 1.37 的 BCCL 文档,您在下面看到的示例看起来不错,但没有工作。我想这算是劣势。

    使用 BCCL,您只能得到静态断言之类的东西,而核心语言概念功能提供完整的模块化类型检查,并且能够防止某些函数模板参与重载决策。使用本机概念,编译器可以立即检查受约束模板的主体,而 BCCL 不会使编译器在这方面检查任何内容。您必须使用“arche type”参数手动实例化您的模板,以查看模板是否使用了任何不可用的操作(例如,前向迭代器上的 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 转换为 long。但实例化失败,因为 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 将 SFINAE 扩展为表达式,以及我们可以编写的函数模板的 decltype 和默认模板参数

    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
    }
    

    在这种情况下,模板参数推导将失败静默,因为编译器不知道表达式 ∗make() 应该是什么类型(我们不能取消引用一个整数)。通过一些模板元编程和一些宏,我们可以非常接近于对模板参数施加任意结构约束以一种可读的方式。假设 REQUIRES 和 RandomAccessIterator 有适当的定义,它可能看起来像这样:

    template <typename Iter
      REQUIRES( RandomAccessIterator<Iter> )
    >
    void foo(Iter,Iter) {}
    

    HTH, S

    【讨论】:

    • 谢谢!但我不能完全相信这一点。我想我在 clc++m 新闻组中看到了 SFINAE 的默认模板参数的使用。
    • 并不是说完整的语言特性会阻止重载参与重载解析;而是完整的语言功能允许根据概念要求选择重载,并与实际参数进行更具体的匹配
    猜你喜欢
    • 2010-10-04
    • 2014-04-03
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 2016-04-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-20
    相关资源
    最近更新 更多