概念库concept

类模板,函数模板,以及非模板函数(通常是类模板的成员),可以与一项约束 相关联,它指定了对模板实参的一些要求,这些要求可以被用于选择最恰当的函数重载和模板特化。
这种要求的具名集合被称为概念。每个概念都是一个谓词,它在编译时求值,并在将之用作约束时成为模板接口的一部分。

concept语法

概念是要求的具名集合。概念的定义必须在命名空间作用域中出现。概念定义拥有以下形式:

template < 模板形参列表 >

concept 概念名 属性 (可选) = 约束表达式;

属性    -    任意数量的属性的序列

概念不能被显式实例化、显式特化或部分特化(不能更改约束的原初定义的含义)。

概念可以在标识表达式中命名。该标识表达式的值在满足约束表达式时是 true,否则是 false。

概念在作为以下内容的一部分时也可以在类型约束中被命名:

         模板类型形参声明
        占位类型说明符
        复合要求

requires语法

requires { 要求序列 }    (1)    

requires ( 形参列表 (可选) ) { 要求序列 }    (2)    
形参列表    -    形参列表
要求序列    -    要求 序列,每个要求都属于以下之一:
   简单要求
   类型要求
   复合要求
   嵌套要求
某个局部形参有默认实参或者形参列表以省略号结尾等是错误的。

 requires可以放在模版中,也可以放在函数之后,但是不可以放在类之后。

concept约束表达式

template < 模板形参列表 >

concept 概念名 属性 (可选) = 约束表达式;

常量表达式

template <typename T>
concept ConExp = sizeof(T) == 4;

requires表达式

requires { requirements; }
requires (parameter-list) { requirements; }
简单要求

简单要求是任何不以关键词 requires 开始的表达式语句。它断言该表达式是有效的。表达式是不求值的操作数;只检查语言的正确性。

template<typename T>
concept Cadd = requires (T a, T b)
{
    a + b; // "需要表达式 “a + b” 是可以通过编译的有效表达式"
};
类型要求

类型要求是关键词 typename 后面接一个可以被限定的类型名称。该要求是,所指名的类型是有效的:可以用来验证某个指名的嵌套类型是否存在,或者某个类模板特化是否指名了某个类型,或者某个别名模板特化是否指名了某个类型。指名类模板特化的类型要求并不要求该类型是完整的。

template <typename T>
concept C = requires {
    typename T::get();  //T具备get成员函数
};

template<typename T>
concept C = requires
{
    typename T::inner; // 需要嵌套成员名
    typename S<T>;     // 需要类模板特化
    typename Ref<T>;   // 需要别名模板替换
};

template<typename T>
concept cOpt = requires(T a, T b)
{
    // 要求a + b的结果可以转换为T类型
    { a + b } -> std::convertible_to<T>;
};
复合要求

{ 表达式 } noexcept(可选) 返回类型要求 (可选) ;    

template<typename T>
concept C2 = requires(T x)
{
    // 表达式 *x 必须合法
    // 并且 类型 T::inner 必须存在
    // 并且 *x 的结果必须可以转换为 T::inner
    {*x} -> std::convertible_to<typename T::inner>;
 
    // 表达式 x + 1 必须合法
    // 并且 std::same_as<decltype((x + 1)), int> 必须满足
    // 即, (x + 1) 必须为 int 类型的纯右值
    {x + 1} -> std::same_as<int>;
 
    // 表达式 x * 1 必须合法
    // 并且 它的结果必须可以转换为 T
    {x * 1} -> std::convertible_to<T>;
};
嵌套要求
template<class T>
concept Semiregular = DefaultConstructible<T> &&
    CopyConstructible<T> && Destructible<T> && CopyAssignable<T> &&
requires(T a, std::size_t n)
{  
    requires Same<T*, decltype(&a)>; // 嵌套:"Same<...> 求值为 true"
    { a.~T() } noexcept; // 复合:"a.~T()" 是不会抛出的合法表达式
    requires Same<T*, decltype(new T)>; // 嵌套:"Same<...> 求值为 true"
    requires Same<T*, decltype(new T[n])>; // 嵌套
    { delete new T }; // 复合
    { delete new T[n] }; // 复合
};

组合concept约束表达式

现有的 Concept 表达式可以通过使用逻辑运算符“与”(&&)和“或”(||)来组合。

template<class T>
concept Integral = std::is_integral<T>::value;
template<class T>
concept SignedIntegral = Integral<T> && std::is_signed<T>::value;
template<class T>
concept UnsignedIntegral = Integral<T> && !SignedIntegral<T>;

template<class T = void>
    requires EqualityComparable<T> || Same<T, void>
struct equal_to;

模板中concept的使用

作为模板参数约束,替换typename

template <ConExp T>
T add(T a, T b)
{
    return a + b;
}

使用requies约束

template <typename T>
requires ConExp<T> // 只能放在类前面,函数模板可以放在函数名后面
class AA 
{
public:
    static T add(T a, T b)
    {
        return a + b;
    }
};

内联requies约束

template <typename T>  
T add3(T a, T b)requires requires(T) { sizeof(T) == 4; }
{
    return a + b;
}

使用标准库提供的 concept约束

核心语言 Concepts:same_as、derived_from、convertible_to、integral、floating_point、copy_constructible 等。

比较 Concepts:equality_comparable、totally_ordered 等。

对象 Concepts:movable、copyable 等。

可调用 Concepts:invocable、predicate 等。

#include <concepts>   //c++20提供std::integral、convertible_to、same_as~~
template <typename T>
    requires std::integral<T>
T add4(T a, T b)
{
    return a + b;
}

结合auto函数重载

std::floating_point  auto add4(std::floating_point  auto a, std::floating_point  auto b)
{
    return a + b;
}

部分参数约束

template <unsigned int i>
    requires (i <= 20)
int add6(int j)
{
    return i + j;
}
//调用:add6<20>(100)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值