C++20之 concept 概念

 概念是在编译期求值,且是bool值。运行期不存在

由bool值,可以进行与或非组件(&&,||,!)

这是一种谓词逻辑

当类型T,满足concept C,即C<T>在编译期计算出来是true,时,编译通过

requires xxx;//如果xxx是false,编译错误  这是require语句

constexpr bool b = requires(){}; //不会编译错误,而是返回一个bool值(可以是true或false) 这是require表达式

requires(){

    2 == 3; //形成一个bool值

    requires 2==3; //编译错误

}

#include <iostream>
#include "common/log.h"
#include <limits>
#include <vector>
#include <span>
#include <array>
#include <type_traits>
#include <cmath>
#include <memory>
#include <variant>
#include <cassert>
#include <concepts>
using namespace AdsonLib;

//概念是在编译期求值,且是bool值。运行期不存在
//由bool值,可以进行与或非组件(&&,||,!)
//当类型T,满足concept C,即C<T>在编译期计算出来是true,时,编译通过
template<typename T>
concept INT = std::is_same_v<T,int> || std::is_same_v<T, long>;

template<typename T>
requires INT<T> //requires子句
struct Foo{
    void Init(int){}
    void Close(double)noexcept{}
    void Show(){}
    using type = T;
    T t;
};
template<INT T> //直接用概念,这里才体现出概念的意义
struct Bar{
    T a;
};
template<> //特化得满足概念要求
struct Bar<long>{
    double a;
};

constexpr int add(int a, int b){
    return a + b;
}
//require子句,定义复杂概念
template<typename T>
concept Machine =  requires(T m) {
    m.Init(0); //普通约束
    {m.Init(std::declval<int>())} -> std::same_as<void>; //大括号对一个块约束
    {m.Close(0.3)}noexcept -> std::same_as<void>;
    typename T::type;
    requires sizeof(T) > 1;
    requires !INT<T>; //require静表式
    requires add(2, 4) > 0; //constexpr
};

//用概念对函数类型和参数约束
INT auto add(INT auto a, INT auto b) {
    return a + b;
}

//利用概念偏特化函数。
void f(std::integral auto t) {std::cout << 1 << std::endl;}
void f(std::unsigned_integral auto t) {std::cout << 2 << std::endl;}

//直接使用标准库中的概念
template <std::integral T1, std::integral T2>
struct Test {
    void Init(){
        if constexpr(requires(T1 a, T2 b){a+b;}){ //在if contexpr中约束类型
            T1 a;
            T2 b;
            a+b;
        }
    }
};

/*requires xxx;//如果xxx是false,编译错误  这是require语句
constexpr bool b = requires(){}; //不会编译错误,而是返回一个bool值(可以是true或false) 这是require表达式
requires(){
    2 == 3; //形成一个bool值
    requires 2==3; //编译错误
}
*/
template<typename T>
requires requires(){  requires std::is_integral_v<T>;}
struct FooBar{};

int main(int argc, char *argv[]) {
    LOG(INFO) << "testing...";
    Foo<int> a;
    Foo<long> b;
    Foo<signed> c;
    static_assert(!Machine<int>);
    static_assert(Machine<Foo<int>>);
    Bar<int> d;
    LOG(INFO) << "add: " << add(3, 2L);
    FooBar<int> f;
}

concept中的的与或非和你想的不一样

#include <iostream>
#include "common/log.h"
#include <limits>
#include <vector>
#include <span>
#include <array>
#include <type_traits>
#include <cmath>
#include <memory>
#include <variant>
#include <cassert>
#include <concepts>
using namespace AdsonLib;
//总纲:约束分为原子约束和组合约束
//原子约束:先看替类型后语法是不是正确。语法不正确直接返回fase.否则再求值。注意非运算!会组成原子约束
//组合约束:A || B    A && B  先拆成原子约束A, 类型替换并求值。 按短路原则, 对原子部分B进行判断(语法检查&&求值)
//组合约束变原子约束:bool() 括号里写约束
//原子约束变组合: 增加间接层:比如!和折叠表达式
template<typename ...Ts>
concept C=(std::is_integral_v<typename Ts::type>||...); //这是原子约束

template<typename T>
concept IntegralWithNestType = std::is_integral_v<typename T::type>;
//这是组合约束:加了间接层
template<typename ...Ts>
concept C2 = (IntegralWithNestType<Ts>||...);


//把组合约束变成原子约束
//约束组合
template<typename T,typename U>
concept C1 = std::is_integral_v<typename T::type> || std::is_integral_v<typename U::type>;
 
//原子约束     用bool()扩起来 
template<typename T,typename U>
concept C3= bool(std::is_integral_v<typename T::type> || std::is_integral_v<typename U::type>);

template<typename T>
struct Animal {
    using type = T;
};
template<typename T>
struct Person {
};
template<typename T>
concept NotNum = !std::is_integral_v<typename T::type>; //T存在type且不是数字. 如果T::type不存在,就失败了,不能通过!来变成true. 这是个原子约束
 
template<typename T>
concept NumType = std::is_integral_v<typename T::type>; 
 
template<typename T>
concept NotNumType = !NumType<T>;                     //T不存在type或者 type不是数字。间接层变成组合约束 !与C的组合
//如果是NotNumType<int>,那么
//首先看 !NumType<T>;整体是个合法的表达。注意不会展开看。
//然后开始求值:NumType<int> = std::is_integral_v<typename T::type>; 是不合法的。因为没有int::type. 
//所以NumType<int>为false,所以!NumType<int>是True.
 
 
 
template<typename T, typename U>
concept NotNumBoth = !std::is_integral_v<typename T::type> && std::is_integral_v<typename U::type>; 
//第一步判断整体是不是语法正确:!std::is_integral_v<typename T::type> 
//    如果没有T::type, 那么NotNumBoth = false。 此时不会进行求值,所以!这不起作用
//第二步:开始求值左边is_integral_v<typename T::type>,再!。如果左边为真,右边求值。短路求值
//对于NotNumBoth<int, double>来说,没有int::type,第一步就直接返回false了。 不会去仔细判断没type,再取非.
//左边判断完成后: 右边开始std::is_integral_v<typename U::type>; 
 

template<typename T, typename U>
concept NotNumOne = std::is_integral_v<typename T::type> || std::is_integral_v<typename U::type>; 
//组合转原子
template<typename T, typename U>
concept NotNumOneAtomic = bool(std::is_integral_v<typename T::type> || std::is_integral_v<typename U::type>);
int main(int argc, char *argv[]) {
    LOG(INFO) << "testing...";
    static_assert(!NotNum<Animal<int>>);
    static_assert(NotNum<Animal<std::string>>);
    static_assert(!NotNum<std::string>);
    static_assert(!NotNum<int>); //NotNum<int>是false. 因为没有int::type
 
    static_assert(!NumType<Animal<std::string>>);
    static_assert(NotNumType<Animal<std::string>>);
    static_assert(NotNumType<int>);
    static_assert(!NotNum<Animal<int>>);
 
    static_assert(!NotNumBoth<int, double>);
    static_assert(!NotNumBoth<Animal<int>, Animal<long>>);
    static_assert(NotNumBoth<Animal<std::string>, Animal<int>>);

    static_assert(NotNumOne<int, Animal<int>>);
    static_assert(!NotNumOneAtomic<int, Animal<int>>);
}

猜你喜欢

转载自blog.csdn.net/wyg_031113/article/details/128307207