概念和模板约束之间有什么区别? [英] What are the differences between concepts and template constraints?

查看:107
本文介绍了概念和模板约束之间有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道C ++完全概念提案和模板约束之间的语义差异是什么(例如,Dlang或新概念 - 针对C ++ 1y的精简提案)。



解决方案

div>


以下信息已过期。


约束提案以合理的深度涵盖了这一点。



概念提案已提交后面的燃烧器在短时间内希望约束(即概念 - 精简)可以在更短的时间尺度被充实和实现,目前旨在至少C ++ 14中的一些东西。约束建议旨在作为对稍后的概念定义的平滑过渡。约束是 概念提议的一部分,是其定义中的必要构成部分。



C ++的概念库设计,Sutton和Stroustrup考虑以下关系:


概念=约束+公理


要快速概述其含义:


  1. 约束 - 对类型的静态可评估属性的谓词。纯语法要求。不是域抽象。

  2. Axioms - 假设为真的类型的语义要求。不静态检查。

  3. 概念 - 对其参数的算法的一般抽象要求。

因此,如果向约束(语法属性)添加公理(语义属性) 。






Concepts-Lite



给我们带来了第一部分,约束,但这是向完全成熟的概念迈出的重要和必要的步骤。



约束



约束是关于语法的。它们给我们一种在编译时静态辨别类型的属性的方法,以便我们可以根据它们的句法属性来限制用作模板参数的类型。在当前的约束建议中,使用诸如&& || 之类的逻辑连接来表达命题演算的子集$ c>。



让我们来看看动作中的约束:

  template< typename Cont> 
需要Sortable< Cont>()
void sort(Cont& container);

这里我们定义一个函数模板 sort 。新增的是 requires子句。 requires子句给出了该函数的模板参数的一些约束。特别是,这个约束说明 Cont 类型必须是 Sortable 类型。一个整洁的事情是,它可以写成一个更简洁的形式,如:

 模板< Sortable Cont> 
void sort(Cont& container);

现在,如果您尝试传递不被认为 Sortable 到这个函数,你会得到一个很好的错误,立即告诉你,推导 T 类型不是一个 Sortable 类型。如果你在C ++ 11中这样做了,你会有一个可怕的错误从里面 sort 函数,没有意义任何人。



约束谓词与类型traits非常相似。他们采取一些模板参数类型,并给你一些信息。约束尝试回答关于类型的以下类型的问题:


  1. 这种类型是否具有这样的操作符重载?

  2. 这些类型可以用作此运算符的操作数吗?

  3. 这种类型是否具有这样的特征?

  4. 这个常量表达式是否等于? (非类型模板参数)

  5. 此类型是否有一个名为yada-yada的函数返回该类型?

  6. 这样的语法需求。相反,他们将携手合作。



    示例



    所以关于约束的重要事情是他们不关心语义一个iota。一些很好的约束示例是:




    • Equality_comparable< T> 检查类型是否具有 == ,并且具有相同类型的两个操作数。


    • Equality_comparable< T,U> :检查给定类型的左和右操作数是否有 == / li>

    • 算术< T> :检查类型是否为算术类型。


    • Floating_point< T> :检查类型是否为浮点类型。


    • Input_iterator< T> :检查类型是否支持输入迭代器必须支持的语法操作。


    • 相同< T,U> :检查给定类型是否相同。




    您可以尝试使用特殊的 GCC概念精简版






    Beyond Concepts-Lite



    一切超越概念 - 精简提案。这比未来本身更具未来感。



    Axioms



    公理都是关于语义。它们指定关系,不变量,复杂性保证和其他这样的事情。让我们来看一个例子。



    虽然 Equality_comparable 约束会告诉你 operator == 需要类型 T U 不告诉你操作是什么意思。为此,我们将有公理 Equivalence_relation 。这个公理说,当这两种类型的对象与 operator == 给出 true 比较时,这些对象是等效的。这可能看起来多余,但它肯定不是。您可以轻松地定义运算符== ,而不是像运算符



    另一个例子是 Greater 公理。很好地说, T 的两个对象可以与> < 运算符,但它们是什么意思 Greater 公理说iff x 大于 y ,那么 y 小于 x 。所提出的规范例如公理如下:

      template< typename T> 
    axiom Greater(T x,T y){
    (x> y)==(y }

    所以公理会回答下列类型的问题:


    1. 这两个操作符之间是否有这种关系?

    2. 这种类型的运算符是否意味着这个?

    3. 此类型的此操作是否有这种复杂性?

    4. 该操作符的结果是否意味着这是真的?

    也就是说,它们完全关心这些类型的类型和操作的语义。这些东西不能被静态检查。



    示例



    以下是公理的一些常见示例:




    • Equivalence_relation :如果两个对象比较 == ,它们是等效的。


    • / code>:每当 x> y ,则 y < $


    • < = y ,然后!(y


    • p> Copy_equality :对于 x y code> T :if x == y ,通过复制构造创建的同一类型的新对象 T {x} == y 仍然 x == y (也就是说,它是非破坏性的)。

      li>


    概念



    现在的概念很容易定义;它们只是约束和公理的组合。它们提供了对类型的语法和语义的抽象要求。



    例如,考虑下面的 Ordered 概念:

     概念Ordered< Regular T> {
    requires constraint Less< T>
    需要公理Strict_total_order< less< T>,T> ;;
    require axiom Greater< T> ;;
    requires axiom Less_equal< T>
    require axiom Greater_equal< T>
    }



    首先注意,对于模板类型 T 有序,它还必须满足常规概念的要求。 Regular 概念是一个非常基本的要求,类型是良好的 - 它可以被构造,销毁,复制和比较。



    除了这些要求之外, Ordered 要求 T 满足一个约束和四个公理: / p>


    • 约束:有序类型必须具有


    • 公理:对于 x

      • x < c> c <>。 y 小于 x ,反之亦然。

      • x 小于或等于 y $ 不小于 x ,反之亦然。

      • < c $ c>大于或等于 y y 不大于 x ,反之亦然。



    这样的公理给了你的概念。它们定义了与算法一起使用的抽象类型的语法和语义要求。算法目前必须假设所使用的类型将支持某些操作并表达某些语义。通过概念,我们将能够确保满足要求。



    最新的概念设计,编译器将只检查一个概念的语法要求是否由模板参数满足。公理未被检查。由于公理表示不能静态评估(或通常不可能完全检查)的语义,因此类型的作者必须明确地声明它们的类型满足概念的所有要求。



    示例



    以下是一些示例的概念:




    • 常规类型是可构造,可破坏,


    • 已订购类型支援运算符<


    • 可复制的类型复制可构造,可破坏,如果 x 等于 y x 被复制,复制也将等于 y


    • Iterator 类型必须具有关联类型 value_type 引用 difference_type iterator_category ,它们本身必须满足某些概念。他们还必须支持运算符++ 并且可解除引用。




    概念之路



    约束是C ++完整概念特性的第一步。它们是非常重要的一步,因为它们提供了类型的静态可执行的需求,这样我们可以编写更清晰的模板函数和类。现在我们可以避免 std :: enable_if 及其元编程朋友的一些困难和丑陋。



    约束建议不会执行的一些事情:


    1. 它不提供概念定义语言。


    2. 约束不是概念图。用户不需要特别注释他们的类型满足某些约束。它们是使用简单编译时语言特性的静态检查。


    3. 模板的实现不受其模板参数的约束。也就是说,如果你的函数模板做任何对象的约束类型,它不应该这样做,编译器没有办法诊断。


    约束建议是专门设计的,概念提案可以在其上面引入。任何运气,这种转变应该是一个相当平稳的骑。概念组正在寻求为C ++ 14引入约束(或在技术报告中不久后),而完整的概念可能会在C ++ 17周围开始出现。


    I want to know what are the semantic differences between the C++ full concepts proposal and template constraints (for instance, constraints as appeared in Dlang or the new concepts-lite proposal for C++1y).

    What are full-fledged concepts capable of doing than template constraints cannot do?

    解决方案

    The following information is out of date. It needs to be updated according to the latest Concepts Lite draft.

    Section 3 of the constraints proposal covers this in reasonable depth.

    The concepts proposal has been put on the back burners for a short while in the hope that constraints (i.e. concepts-lite) can be fleshed out and implemented in a shorter time scale, currently aiming for at least something in C++14. The constraints proposal is designed to act as a smooth transition to a later definition of concepts. Constraints are part of the concepts proposal and are a necessary building block in its definition.

    In Design of Concept Libraries for C++, Sutton and Stroustrup consider the following relationship:

    Concepts = Constraints + Axioms

    To quickly summarise their meanings:

    1. Constraint - A predicate over statically evaluable properties of a type. Purely syntactic requirements. Not a domain abstraction.
    2. Axioms - Semantic requirements of types that are assumed to be true. Not statically checked.
    3. Concepts - General, abstract requirements of algorithms on their arguments. Defined in terms of constraints and axioms.

    So if you add axioms (semantic properties) to constraints (syntactic properties), you get concepts.


    Concepts-Lite

    The concepts-lite proposal brings us only the first part, constraints, but this is an important and necessary step towards fully-fledged concepts.

    Constraints

    Constraints are all about syntax. They give us a way of statically discerning properties of a type at compile-time, so that we can restrict the types used as template arguments based on their syntactic properties. In the current proposal for constraints, they are expressed with a subset of propositional calculus using logical connectives like && and ||.

    Let's take a look at a constraint in action:

    template <typename Cont>
      requires Sortable<Cont>()
    void sort(Cont& container);
    

    Here we are defining a function template called sort. The new addition is the requires clause. The requires clause gives some constraints over the template arguments for this function. In particular, this constraint says that the type Cont must be a Sortable type. A neat thing is that it can be written in a more concise form as:

    template <Sortable Cont>
    void sort(Cont& container);
    

    Now if you attempt to pass anything that is not considered Sortable to this function, you'll get a nice error that immediately tells you that the type deduced for T is not a Sortable type. If you had done this in C++11, you'd have had some horrible error thrown from inside the sort function that makes no sense to anybody.

    Constraints predicates are very similar to type traits. They take some template argument type and give you some information about it. Constraints attempt to answer the following kinds of questions about type:

    1. Does this type have such-and-such operator overloaded?
    2. Can these types be used as operands to this operator?
    3. Does this type have such-and-such trait?
    4. Is this constant expression equal to that? (for non-type template arguments)
    5. Does this type have a function called yada-yada that returns that type?
    6. Does this type meet all the syntactic requirements to be used as that?

    However, constraints are not meant to replace type traits. Instead, they will work hand in hand. Some type traits can now be defined in terms of concepts and some concepts in terms of type traits.

    Examples

    So the important thing about constraints is that they do not care about semantics one iota. Some good examples of constraints are:

    • Equality_comparable<T>: Checks whether the type has == with both operands of that same type.

    • Equality_comparable<T,U>: Checks whether there is a == with left and right operands of the given types

    • Arithmetic<T>: Checks whether the type is an arithmetic type.

    • Floating_point<T>: Checks whether the type is a floating point type.

    • Input_iterator<T>: Checks whether the type supports the syntactic operations that an input iterator must support.

    • Same<T,U>: Checks whether the given type are the same.

    You can try all this out with a special concepts-lite build of GCC.


    Beyond Concepts-Lite

    Now we get into everything beyond the concepts-lite proposal. This is even more futuristic than the future itself. Everything from here on out is likely to change quite a bit.

    Axioms

    Axioms are all about semantics. They specify relationships, invariants, complexity guarantees, and other such things. Let's look at an example.

    While the Equality_comparable<T,U> constraint will tell you that there is an operator== that takes types T and U, it doesn't tell you what that operation means. For that, we will have the axiom Equivalence_relation. This axiom says that when objects of these two types are compared with operator== giving true, these objects are equivalent. This might seem redundant, but it's certainly not. You could easily define an operator== that instead behaved like an operator<. You'd be evil to do that, but you could.

    Another example is a Greater axiom. It's all well and good to say two objects of type T can be compared with > and < operators, but what do they mean? The Greater axiom says that iff x is greater then y, then y is less than x. The proposed specification such an axiom looks like:

    template<typename T>
    axiom Greater(T x, T y) {
      (x>y) == (y<x);
    }
    

    So axioms answer the following types of questions:

    1. Do these two operators have this relationship with each other?
    2. Does this operator for such-and-such type mean this?
    3. Does this operation on that type have this complexity?
    4. Does this result of that operator imply that this is true?

    That is, they are concerned entirely with the semantics of types and operations on those types. These things cannot be statically checked. If this needs to be checked, a type must in some way proclaim that it adheres to these semantics.

    Examples

    Here are some common examples of axioms:

    • Equivalence_relation: If two objects compare ==, they are equivalent.

    • Greater: Whenever x > y, then y < x.

    • Less_equal: Whenever x <= y, then !(y < x).

    • Copy_equality: For x and y of type T: if x == y, a new object of the same type created by copy construction T{x} == y and still x == y (that is, it is non-destructive).

    Concepts

    Now concepts are very easy to define; they are simply the combination of constraints and axioms. They provide an abstract requirement over the syntax and semantics of a type.

    As an example, consider the following Ordered concept:

    concept Ordered<Regular T> {
      requires constraint Less<T>;
      requires axiom Strict_total_order<less<T>, T>;
      requires axiom Greater<T>;
      requires axiom Less_equal<T>;
      requires axiom Greater_equal<T>;
    }
    

    First note that for the template type T to be Ordered, it must also meet the requirements of the Regular concept. The Regular concept is a very basic requirements that the type is well-behaved - it can be constructed, destroyed, copied and compared.

    In addition to those requirements, the Ordered requires that T meet one constraint and four axioms:

    • Constraint: An Ordered type must have an operator<. This is statically checked so it must exist.
    • Axioms: For x and y of type T:
      • x < y gives a strict total ordering.
      • When x is greater than y, y is less than x, and vice versa.
      • When x is less than or equal to y, y is not less than x, and vice versa.
      • When x is greater than or equal to y, y is not greater than x, and vice versa.

    Combining constraints and axioms like this gives you concepts. They define the syntactic and semantic requirements for abstract types for use with algorithms. Algorithms currently have to assume that the types used will support certain operations and express certain semantics. With concepts, we'll be able to ensure that requirements are met.

    In the latest concepts design, the compiler will only check that the syntactic requirements of a concept are fulfilled by the template argument. The axioms are left unchecked. Since axioms denote semantics that are not statically evaluable (or often impossible to check entirely), the author of a type would have to explicitly state that their type meets all the requirements of a concept. This was known as concept mapping in previous designs but has since been removed.

    Examples

    Here are some examples of concepts:

    • Regular types are constructable, destructable, copyable, and can be compared.

    • Ordered types support operator<, and have a strict total ordering and other ordering semantics.

    • Copyable types are copy constructable, destructable, and if x is equal to y and x is copied, the copy will also compare equal to y.

    • Iterator types must have associated types value_type, reference, difference_type, and iterator_category which themselves must meet certain concepts. They must also support operator++ and be dereferenceable.

    The Road to Concepts

    Constraints are the first step towards a full concepts feature of C++. They are a very important step, because they provide the statically enforceable requirements of types so that we can write much cleaner template functions and classes. Now we can avoid some of the difficulties and ugliness of std::enable_if and its metaprogramming friends.

    However, there are a number of things that the constraints proposal does not do:

    1. It does not provide a concept definition language.

    2. Constraints are not concept maps. The user does not need to specifically annotate their types as meeting certain constraints. They are statically checked used simple compile-time language features.

    3. The implementations of templates are not constrained by the constraints on their template arguments. That is, if your function template does anything with an object of constrained type that it shouldn't do, the compiler has no way to diagnose that. A fully featured concepts proposal would be able to do this.

    The constraints proposal has been designed specifically so that a full concepts proposal can be introduced on top of it. With any luck, that transition should be a fairly smooth ride. The concepts group are looking to introduce constraints for C++14 (or in a technical report soon after), while full concepts might start to emerge sometime around C++17.

    这篇关于概念和模板约束之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆