C++模板基础(七)

Concept

-模板的问题:没有对模板参数引入相应的限制
-参数是否可以正常工作,通常需要阅读代码来理解

#include
#include
template<typename T>
void fun()
{
	//...阅读代码来理解
}
int main()
{
	std::vector<int&> x; //“”: 指向引用的指针非法
	return 0;
}

(C++20)Concept:编译期谓词,基于给定的输入,返回true或false
-与constraints(requires语句)一起使用限制模板参数,通常置于模板参数后面的尖括号后面进行限制

#include
#include
#include
template<typename T>
concept IsAvail = std::is_same_v<T, int> || std::is_same_v<T, float>;

template<typename T>
requires IsAvail<T>
void fun(T input)
{
}
int main()
{
  fun(1); //OK
  fun(3.14); //OK
  fun(bool); //Error: candidate template ignored: constraints not satisfied
  return 0;
}

Concept的定义与使用
-包含一个模板参数的Concept
-使用requires语句
-直接替换typename

#include
#include
#include
template<typename T>
concept IsAvail = std::is_same_v<T, int> || std::is_same_v<T, float>;

template<IsAvail T>
void fun(T input)
{
}
int main()
{
  fun(1); //OK
  fun(3.14); //OK
  return 0;
}

包含多个模板参数的Concept

#include
#include
#include
template<typename T, typename T2>
concept IsAvail = std::is_same_v<T, T2>;

template<typename T>
void fun(T input)
{
}
int main()
{
  std::cout << IsAvail<int, float> << std::endl;
  return 0;
}
#include
#include
#include
template<typename T, typename T2>
concept IsAvail = std::is_same_v<T, T2>;

template<typename T, typename T2>
requires IsAvail<T, T2>
void fun(T input, T2 input2)
{
  
}
int main()
{
  fun(3, 3.14); //Error: candidate template ignored: constraints not satisfied
  fun(3, 5); //OK
  return 0;
}
#include
#include
#include
template<typename T, typename T2>
concept IsAvail = std::is_same_v<T, T2>;

template<typename T>
requires IsAvail<T, int>
void fun(T input)
{
  
}
int main()
{
  fun(3); //OK
  fun(3.14); //andidate template ignored: constraints not satisfied
  return 0;
}

-用作类型constraints时,少传递一个参数,推导出的类型将作为首个参数

requires表达式
-简单表达式:表明可以接收的操作

#include
#include
#include
template<typename T>
concept Addable = requires(T a, T b) { a + b; };

template<Addable T>
auto fun(T x, T y)
{
	return x + y;
}
int main()
{
  fun(3, 5);
	return 0;
}

-类型表达式:表明是一个有效的类型

#include
#include
#include
template<typename T>
concept Addable = requires(T a, T b) { a + b; };

template<Addable T>
auto fun(T x, T y)
{
	return x + y;
}

struct Str {};
int main()
{
  fun(3, 5); //OK
  
  Str a;
  Str b;
  fun(a, b); //Error: candidate template ignored: constraints not satisfied
  return 0;
}
#include
#include
#include
template<typename T>
concept Avail = 
requires{
	typename T::inter;
};

template<Avail T>
auto fun(T x)
{
}

struct Str
{
	using inter = int;
};
int main()
{
  fun(2); //Error: unknown type name 'T' auto fun(T x)
  fun(Str{}); //OK
  return 0;
}

-复合表达式:表明操作的有效性,以及返回类型的特性

#include
#include
#include
template<typename T>
concept Avail = 
requires (T x){
	{ x + 1 }->int;
};

template<Advail T>
auto fun(T x)
{
}

struct Str
{
	using inter = int;
};
int main()
{
	fun(3); //OK
	fun(Str{}); //Error: expected concept name with optional arguments { x + 1 }->int;
	return 0;
}

-嵌套表达式:包含其它的限定表达式
注意区分requires从句与requires表达式
requires从句会影响重载解析与特化版本的选取

#include
#include
#include

template<typename T>
requires std::is_same_v<T, int>
void fun(T)
{

}

int main()
{
	fun(3); //OK
	return 0;
}
#include
#include
#include

template<typename T>
requires std::is_same_v<T, float>
void fun(T)
{

}

int main()
{
	fun(3); //Error: candidate template ignored: constraints not satisfied
	return 0;
}

-只有requires从句有效而且返回为true时相应的模板才会被考虑

#include
#include
#include
template<typename T>
requires std::is_same_v<T, int>
void fun(T)
{
	std::cout << "template requires std::is_same_v void fun(T)\n";
}

template<typename T>
requires std::is_same_v<T, float>
void fun(T)
{
	std::cout << "template requires std::is_same_v void fun(T)\n";
}

int main()
{
	fun(3); //输出template requires std::is_same_v void fun(T)
	return 0;
}

-requires从句所引入的限定具有偏序特性,系统会选择限制最严格的版本

#include
#include
#include
template<typename T>
concept C1 = std::is_same_v<T, int>;

template<typename T>
concept C2 = std::is_same_v<T, int> || std::is_same_v<T, float>;

template<C1 T>
void fun(T)
{
	std::cout << "template void fun(T)\n";
}

template<C2 T>
void fun(T)
{
	std::cout << "template void fun(T)\n";
}

int main()
{
	fun(3); //输出template void fun(T)
	return 0;
}

偏特化小技巧:在声明中引入"A||B"进行限制,之后分别针对A与B引入特化

#include
#include
#include
template<typename T>
class B;

template<>
class B<int> {};

template<>
class B<float> {};
int main()
{
	B<double> x; //Error: “x”使用未定义的 class“B
	return 0;
}
#include
#include
#include
template<typename T>
	requires std::is_same<T, int> || std::is_same_v<T, float>
	//等同于requires std::is_integral_v || std::is_floating_point_v
class B;

template<>
class B<int> {};

template<>
class B<float> {};
int main()
{
	B<double> x; //Error: template constraints failure
	return 0;
}
#include
#include
#include
template<typename T>
	requires std::is_integral_v<T> || std::is_floating_point_v<T>
class B;

template<typename T>
requires std::is_integral_v<T>
class B<T> {}; //class B {}; 不是特化

template<typename T>
requires std::is_floating_point_v<T>
class B<T> {}; //class B {}; 不是特化

struct Str {};
int main()
{
	B<double> x; //Error: aggregate 'B x' has incomplete type and can not be defined
	B<Str> y; //Error: template constraints failure
	return 0;
}

参考
深蓝学院: C++基础与深度解析
约束与概念 (C++20 起)

你可能感兴趣的:(c++,c语言,开发语言)