C++

C++20:概念之细节

2020-02-27  本文已影响0人  奇点创客

原文详见:C++20: Concepts, the Details

在我的上一篇文章 C++20:两个极端和概念的救赎中,我给出了概念的第一个动机:概念对模板参数进行语义约束。今天,我将以紧凑的形式来介绍概念的不同用例。

细节

只要记住这一点:概念的优点是什么?

这篇文章是关于前三点的。让我们来看看概念的许多不同用法:

三种方式

有三种使用可排序概念的方式。为了简单起见,我仅显示函数模板的声明。

制约条件
template<typename Cont>
    requires Sortable<Cont>
void sort(Cont& container);
尾随制约条件
template<typename Cont>
void sort(Cont& container) requires Sortable<Cont>;
受制约的模板参数
template<Sortable Cont>
void sort(Cont& container)

在这种情况下,算法排序要求容器是可排序的。 Sortable 必须是一个常量表达式和一个谓词。

你可以定义仅接受对象的类模板。

template<Object T>
class MyVector{};

MyVector<int> v1;   // OK
MyVector<int&> v2;  // ERROR: int& does not satisfy the constraint Object

编译器会抱怨引用不是对象。也许您想知道,什么是对象? std::is_object 的实现 -- 类型萃取函数可能已经给出了答案:

template< class T>
struct is_object : std::integral_constant<bool,
                     std::is_scalar<T>::value ||
                     std::is_array<T>::value  ||
                     std::is_union<T>::value  ||
                     std::is_class<T>::value> {};

对象可以是标量,也可以是数组,也可以是联合或类。

成员函数

template<Object T>
class MyVector{
    ... 
    void push_back(const T& e) requires Copyable<T>{}
    ...
};

在这种情况下,成员函数要求模板参数T必须是可复制的(Copyable)。

可变参数模板

// allAnyNone.cpp

#include <iostream>
#include <type_traits>

template<typename T>
concept Arithmetic = std::is_arithmetic<T>::value;

template<Arithmetic... Args>
bool all(Args... args) { return (... && args); }

template<Arithmetic... Args>
bool any(Args... args) { return (... || args); }

template<Arithmetic... Args>
bool none(Args... args) { return !(... || args); }

int main(){

    std::cout << std::boolalpha << std::endl;
               
    std::cout << "all(5, true, 5.5, false): " << all(5, true, 5.5, false) << std::endl;  

    std::cout << "any(5, true, 5.5, false): " << any(5, true, 5.5, false) << std::endl; 
              
    std::cout << "none(5, true, 5.5, false): " << none(5, true, 5.5, false) << std::endl;     
    
}

你可以在可变参数模板中使用概念。函数模板的定义基于折叠表达式。all、any 和 none 都需要类型参数 T 来支持 Arithmetic(算术) 概念。Arithmetic 概念的本质意味着 T 不是整数就是浮点数。

全新的 Microsoft 编译器 19.23 仅部分支持概念提案的语法。

多个要求

当然,你可以对模板参数使用多个要求。

template <SequenceContainer S,   
          EqualityComparable<value_type<S>> T>
Iterator_type<S> find(S&& seq, const T& val){
    ...
}

函数模板的 find 要求容器 S 是SequenceContainer(序列容器),并且其元素是EqualityComparable(可相等比较的)。

重载

std::advance(iter, n) 会增加给定的迭代器 iter 以 n 个元素的步长。根据迭代器的不同,实现可以使用指针算术,也可以依次执行 n 次增加。在第一种情况下,执行时间是常数;在第二种情况下,执行时间取决于步骤大小 n。由于概念,您可以针对迭代器的不同种类将 std::advance 重载。

template<InputIterator I>
void advance(I& iter, int n){...}

template<BidirectionalIterator I>
void advance(I& iter, int n){...}

template<RandomAccessIterator I>
void advance(I& iter, int n){...}

// usage

std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto vecIt = vec.begin();
std::advance(vecIt, 5);       //  RandomAccessIterator

std::list<int> lst{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto lstIt = lst.begin();
std::advance(lstIt, 5);       //  BidirectionalIterator

std::forward_list<int> forw{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto forwIt = forw.begin();
std::advance(forwIt, 5);      //  InputIterator

根据迭代器种类的不同,对容器 std::vector,std::list 和 std :: forward_list 的支持将匹配到最合适的 std :: advance 实现。

特化

概念还支持模板特化

template<typename T>
class MyVector{};

template<Object T>
class MyVector{};

MyVector<int> v1;     // Object T
MyVector<int&> v2;    // typename T

接下来?

我的下一篇文章是关于 C++20 的语法统一。使用 C++20,您可以在每个地方使用受约束的占位符(concept),或者以 C++11 的方式使用不受约束的占位符(auto)。但这并不是统一的结束。用 C++20 定义模板变得非常简单,只需在函数的声明中使用带约束或不带约束的占位符即可。

上一篇下一篇

猜你喜欢

热点阅读