cpp0x 概念历史

C++0x 概念 — 历史常见问题解答

C++0x “概念” 发生了什么?

它们对于 C++0x/C++11 来说过于复杂,因此从该标准中移除,以便继续对其进行简化以用于未来的标准。这项工作一直在进行中,一个经过彻底简化的版本“Concepts Lite”将作为技术规范成为 C++14 交付物的一部分。

“概念”是一种旨在精确规范模板参数要求的功能。不幸的是,委员会决定进一步研究概念可能会严重延迟 C++0x/C++11 标准,并投票将该功能从工作草案中移除。有关解释,请参阅 Stroustrup 的笔记《C++0x “移除概念” 决定》和《DevX 对 Stroustrup 关于概念及其对 C++0x 影响的采访》。

本常见问题解答中保留了 C++0x 时代的“概念”部分,作为历史信息。

什么是 C++0x 概念?

注意:这是一个历史部分。“C++0x 概念”并未进入 C++11,正在进行彻底的重新设计。

“概念”是一种描述类型、类型组合以及类型和整数组合要求的机制。它对于尽早检查模板的使用特别有用。反过来,它也有助于尽早发现模板主体中的错误。考虑标准库算法 fill

    template<ForwardIterator Iter, class V>          // types of types
        requires Assignable<Iter::value_type,V>  // relationships among argument types
    void fill(Iter first, Iter last, const V& v);       // just a declaration, not definition


    fill(0, 9, 9.9);        // Iter is int; error: int is not a ForwardIterator
                    //                     int does not have a prefix *
    fill(&v[0], &v[9], 9.9);    // Iter is int; ok: int* is a ForwardIterator

请注意,我们只声明了 fill();我们没有定义它(提供它的实现)。另一方面,我们明确说明了 fill() 对其参数的要求

  • 参数 firstlast 必须是 ForwardIterator 类型(并且它们必须是相同类型)。
  • 第三个参数 v 必须是可赋值给 ForwardIteratorvalue_type 的类型。

当然,我们读过标准,所以我们知道这一点。然而,编译器不读取需求文档,所以我们必须在代码中使用 ForwardIteratorAssignable 概念来告诉它。结果是,fill() 使用中的错误会立即在使用点捕获,并且错误消息也得到了极大改进。编译器现在拥有关于程序员意图的信息,以便进行良好的检查和诊断。

概念也有助于模板实现者。考虑

    template<ForwardIterator Iter, class V>
        requires Assignable<Iter::value_type,V>
    void fill(Iter first, Iter last, const V& v)
    {
        while (first!=last) {
            *first = v;
            first=first+1;  // error: + not defined for Forward_iterator
                    // (use ++first)
        }
    }

此错误会立即捕获,从而消除了大量繁琐的测试(当然并非所有测试)。

能够对不同类型的类型进行分类和区分,我们可以根据传入的类型进行重载。例如

    // iterator-based standard sort (with concepts):
    template<Random_access_iterator Iter>
        requires Comparable<Iter::value_type>
    void sort(Iter first, Iter last); // use the usual implementation

    // container-based sort:
    template<Container Cont>
        requires Comparable<Cont::value_type>
    void sort(Cont& c)
    {
        sort(c.begin(),c.end());    // simply call the iterator version
    }

    void f(vector<int>& v)
    {
        sort(v.begin(), v.end());   // one way
        sort(v);                    // another way
        // ...
    }

您可以定义自己的概念,但首先,标准库提供了各种有用的概念,例如 ForwardIteratorCallableLessThanComparableRegular

注意:C++0x 标准库是使用概念指定的。

另请参见

什么是 C++0x 概念映射?

注意:这是一个历史部分。“C++0x 概念”并未进入 C++11,正在进行彻底的重新设计。

一个 int* 是一个 ForwardIterator;我们在介绍概念时说过,标准一直都是这么说的,甚至 STL 的第一个版本也使用指针作为迭代器。然而,我们也谈到了 ForwardIteratorvalue_type。但是 int* 没有名为 value_type 的成员;事实上,它没有成员。那么 int* 怎么会是 ForwardIterator 呢?这是因为我们说它是。使用 concept_map,我们说当 T* 在需要 ForwardIterator 的地方使用时,我们将其 T 视为其 value_type

    template<Value_type T> 
    concept_map ForwardIterator<T*> {     // T*'s value_type is T
        typedef T value_type;
    };

concept_map 允许我们说明我们希望如何看待一种类型,从而省去了修改它或将其包装成新类型的麻烦。“概念映射”是一种非常灵活和通用的机制,用于使独立开发的软件适应通用用途。

另请参见

什么是 C++0x 公理?

注意:这是一个历史部分。“C++0x 概念”并未进入 C++11,正在进行彻底的重新设计。

axiom 是一组谓词,用于指定概念的语义。公理的主要用例是外部工具(例如,不是常见的编译器操作),例如用于领域特定优化的工具(用于指定程序转换的语言是公理动机的重要组成部分)。次要用途只是在标准中精确地指定语义(如在标准库规范的许多部分中使用)。公理对于某些优化(由编译器和传统优化器完成)也可能有用,但编译器不需要注意用户提供的公理;它们根据标准定义的语义工作。

axiom 列出了可以被认为是等效的计算对。考虑

    concept Semigroup<typename Op, typename T> : CopyConstructible<T> {
        T operator()(Op, T, T);
        axiom Associativity(Op op, T x, T y, T z) {
            op(x, op(y, z)) <=> op(op(x, y), z);    // T's operator may be assumed to be associative
        }
    }

    concept Monoid<typename Op, typename T> : Semigroup<Op, T> {    // a monoid is a semigroup with an identity element
        T identity_element(Op);
        axiom Identity(Op op, T x) {
            op(x, identity_element(op)) <=> x;
            op(identity_element(op), x) <=> x;
        }
    }

<=> 是等效运算符,仅在公理中使用。请注意,您不能(通常)证明公理;我们使用公理来陈述我们无法证明但程序员可以陈述为可接受的假设的内容。请注意,对于某些值,等效语句的两边可能都是非法的,例如对浮点类型使用 NaN(非数字):如果等效的两边都使用 NaN,则两者(显然)都无效且等效(与公理所说的无关),但如果只有一边使用 NaN,则可能有机会利用公理。

公理是一系列等效语句(使用 <=>)和条件语句(形式为“if (something) 则我们可以假设以下等效”)

    // in concept TotalOrder:
    axiom Transitivity(Op op, T x, T y, T z)
    {
        if (op(x, y) && op(y, z)) op(x, z) <=> true;    // conditional equivalence 
    }

另请参见

  • C++ 草案 14.9.1.4 公理