> 文章列表 > C++模板基础(七)

C++模板基础(七)

C++模板基础(七)

Concept

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

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

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

#include<iostream>
#include<vector>
#include<type_traits>
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); //OKfun(3.14); //OKfun(bool); //Error: candidate template ignored: constraints not satisfiedreturn 0;
}

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

#include<iostream>
#include<vector>
#include<type_traits>
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); //OKfun(3.14); //OKreturn 0;
}

包含多个模板参数的Concept

#include<iostream>
#include<vector>
#include<type_traits>
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<iostream>
#include<vector>
#include<type_traits>
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 satisfiedfun(3, 5); //OKreturn 0;
}
#include<iostream>
#include<vector>
#include<type_traits>
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); //OKfun(3.14); //andidate template ignored: constraints not satisfiedreturn 0;
}

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

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

#include<iostream>
#include<vector>
#include<type_traits>
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<iostream>
#include<vector>
#include<type_traits>
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); //OKStr a;Str b;fun(a, b); //Error: candidate template ignored: constraints not satisfiedreturn 0;
}
#include<iostream>
#include<vector>
#include<type_traits>
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{}); //OKreturn 0;
}

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

#include<iostream>
#include<vector>
#include<type_traits>
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); //OKfun(Str{}); //Error: expected concept name with optional arguments { x + 1 }->int;return 0;
}

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

#include<iostream>
#include<vector>
#include<type_traits>template<typename T>
requires std::is_same_v<T, int>
void fun(T)
{}int main()
{fun(3); //OKreturn 0;
}
#include<iostream>
#include<vector>
#include<type_traits>template<typename T>
requires std::is_same_v<T, float>
void fun(T)
{}int main()
{fun(3); //Error: candidate template ignored: constraints not satisfiedreturn 0;
}

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

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
requires std::is_same_v<T, int>
void fun(T)
{std::cout << "template<typename T> requires std::is_same_v<T, int> void fun(T)\\n";
}template<typename T>
requires std::is_same_v<T, float>
void fun(T)
{std::cout << "template<typename T> requires std::is_same_v<T, float> void fun(T)\\n";
}int main()
{fun(3); //输出template<typename T> requires std::is_same_v<T, int> void fun(T)return 0;
}

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

#include<iostream>
#include<vector>
#include<type_traits>
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<C1 T> void fun(T)\\n";
}template<C2 T>
void fun(T)
{std::cout << "template<C2 T> void fun(T)\\n";
}int main()
{fun(3); //输出template<C1 T> void fun(T)return 0;
}

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

#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>
class B;template<>
class B<int> {};template<>
class B<float> {};
int main()
{B<double> x; //Error: “x”使用未定义的 class“B<double>”return 0;
}
#include<iostream>
#include<vector>
#include<type_traits>
template<typename T>requires std::is_same<T, int> || std::is_same_v<T, float>//等同于requires std::is_integral_v<T> || std::is_floating_point_v<T>
class B;template<>
class B<int> {};template<>
class B<float> {};
int main()
{B<double> x; //Error: template constraints failurereturn 0;
}
#include<iostream>
#include<vector>
#include<type_traits>
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<double> x' has incomplete type and can not be definedB<Str> y; //Error: template constraints failurereturn 0;
}

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