概念是在编译期求值,且是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>>);
}