兰州做网站的公司有哪些,wordpress上站工具,开发一个网站系统报价,wordpress用户私信功能c模板包括#xff1a;类模板、类#xff08;非模板类和模板类#xff09;方法模板、函数模板、别名模板、变量模板。 类模板模板参数列表说明#xff1a; 1#xff09;类定义 仅模板参数列表声明#xff0c;template行。 类名后无需参数说明。 2#xf… c模板包括类模板、类非模板类和模板类方法模板、函数模板、别名模板、变量模板。 类模板模板参数列表说明 1类定义 仅模板参数列表声明template行。 类名后无需参数说明。 2类方法定义 在类外面定义方法时方法名前需要类型限定类名后面需要类型说明。包括所有未特化模板参数和特化模板参数。 可能全都是未特化参数、全部特化参数、特化参数未特化参数 同时在首行需要template类型声明。 3类实例化 不需要template声明。 只需要类名和后面的类型说明和定义时不同此时需要提供具体的类型。 4template中只包含未特化、未实例化参数。 类名后的参数列表中可包含未实例化参数和特化参数
// 1. 类模板
// TempClass temp(1, 2);
template typename T, typename U
class TempClass {
pulibc:TempClass(T a, U b) {cout basic template\n;}
}// 2. 类方法模板
// 2.1 非模板类的模板方法
// NonTempClass non_temp;
// non_temp.func1(123);
// non_temp.func2(456);
class NonTempClass {
public:// 在类中直接定义模板方法templatetypename Tvoid func1(T t) {cout NonTempClass::func1: t endl;}// 在类中仅声明模板方法在类外面实现templatetypename T void func2(T t);
}
// 在类外面实现模板方法
templatetypename T
void NonTempClass::func2(T t) {cout NonTempClass::func2: t endl;
}// 2.2 模板类的模板方法
templatetypename T, typename U
class TempClass {
public:// 在类内部实现模板方法templatetypename Nvoid func1(N n) {cout TempClass::func1: n endl;}// 仅声明方法templatetypename N void func2(N n);
}// 在类外部定义模板方法注意需要两个template关键字第一个是模板类的第二个是函数模板
templatetypename T, typename U // ----- 类模板的类型参数第一个template关键字
templatetypename N // ----- 函数模板的类型参数第二个template关键字
void TempClass::func2(N n) {cout TempClass::func2: n endl;
}// 3. 函数模板
templatetypename T, typename U
void temp_func(T t, U u) {cout temp_func: t u endl;
}别名模板 1用于为类模板定义别名。函数模板不可用只能为类型定义别名typedef不能用于函数。 2如果类模板完全特化所有参数都明确则不需要提供模板参数声明template就不用别名模板。 3如果类模板偏特化部分参数不确定需要提供模板参数声明template此时用模板别名。
// 4. 别名模板 alias template
// 为上面定义的TempClass模板声明一个别名模板类似模板偏特化的语法
templatetypename U
using AliasClass TempClassstring, U;// 5. 变量模板
templatetypename T
constexpr T pi { T {3.1415} };float fPi { pifloat };
auto ldPi { pilong double };编译器处理模板和选择性实例化 1编译器不编译模板会检查语法错误。 2在模板实例化时用具体类型替换类型参数生成实际代码。 3选择性实例化编译器不会生成所有方法的代码。 1所有虚方法都会生成。 2非虚方法只有被调用的才会生成。 4选择性实例化缺点忽略错误不能及时发现。 5解决显式模板实例化
Gridint grid; // 选择性实例化template class Gridint; // 显示实例化3种模板参数类型参数、非类型参数、template template参数 这3种参数是不同维度的尤其是类型参数和template template参数容易混淆在实例化时需要区分模板参数和普通类型参数如果定义为模板参数则只能提供模板名不能用具体类型实例化如vector不是vector int 1类模板和函数模板都可以使用非类型参数。 2非类型参数支持有限类型整型 / 枚举、指针 / 引用 / nullptr_t、auto / auto / auto*、float、class后2种在C支持有限制 3非类型参数需要使用constexpr可编译时求值的数值或表达式。所有模板参数都需要在编译器确定。 4类型参数和非类型参数都可以提供默认值。 注意匿名模板参数也可以设置默认值类型或非类型参数都可以。 5模板非类型参数其类型可以使用模板的类型参数指定的类型 6匿名参数在模板参数列表中定义匿名参数这些参数在模板定义中没有用到仅用于静态分发通过类型选择不同的模板或者为了应用SFINAE规则阻止生成不符合某些规则的模板。同时匿名模板参数可以提供默认值。
constexpr int a 100;
constexpr int b 200;
// 类模板提供模板参数默认值constexpr
templatetypename Tint, int nab
struct NonTypeArgClass {NonTypeArgClass() {cout NonTypeArg: n n endl;}
};// 函数模板提供模板参数默认值
templatetypename Tint, int n2
void NonTypeArgFunc() {cout NonTypeArgFunc: n n endl;
}NonTypeArgClassstring, 10 nonTypeArg1; // 实例化时提供全部参数
NonTypeArgClassstring nonTypeArg2; // 只提供类型参数非类型参数使用默认值
// NonTypeArgClass15 nonTypeArg2; // comiplation error如果一个参数使用非默认值它前面的参数也不能使用默认值和函数参数默认值一致
NonTypeArgClass nonTypeArg3; // 都使用默认值
NonTypeArgClass nonTypeArg4; // nonTypeArg3和nonTypeArg4完全相同NonTypeArgFuncstring, 20(); // 实例化时提供全部参数
NonTypeArgFuncstring(); // 只提供类型参数非类型参数使用默认值
// NonTypeArgFunc25(); // compilation error
NonTypeArgFunc(); // 和下面的调用效果完全相同
NonTypeArgFunc();// NonTypeArg: n10 // nonTypeArg1
// NonTypeArg: n300 // nonTypeArg2在类定义中没有用到T结果中体现不出差别
// NonTypeArg: n300 // nonTypeArg3
// NonTypeArg: n300 // nonTypeArg4// NonTypeArgFunc: n20 // NonTypeArgFuncstring, 20();
// NonTypeArgFunc: n2 // NonTypeArgFuncstring();
// NonTypeArgFunc: n2 // NonTypeArgFunc();
// NonTypeArgFunc: n2 // NonTypeArgFunc();// 类模板
// 第一个参数是类型参数第二个参数是非类型参数
// 第二个参数的类型使用的类型是模板参数指定的类型并且设置为T的默认值T()或T{ }
templatetypename T, const T defaultVal T()
class Grid {...}// template template 参数模板的类型参数是另一个模板
// c17后class可用typename
template..., templateparameter-list class ParameterName, ...// 如下实例化类型重复且没有约束可能错误写成不同类型
Gridint, vectoroptionalint grid;// 以下语法不能通过编译vector是模板不是类型编译器不知道需要用int实例化vector
Gridint, vector grid;// vector容器定义原型
// vector模板的类型是除去名称vector外剩余的部分这些可作为模板类型参数使用
templatetypename E, typename Allocator std::allocatorE
class vector {...}// 类模板定义
// 复制模板声明把模板名称vector改为类型参数名作为模板参数template
// c17后模板类型参数中的class可换为typenameclass Container - typename Container
// 在模板类型中只使用关键字typename即可
// 模板参数默认类型为vector不是vectorTContainer是一个模板名不是类型名所以要对应vector
templatetypename T,templatetypename T, typename Allocator std::allocatorE class Container std::vector
class Grid {
private:// 定义中使用template template参数// Container是模板的模板类型参数它用optionalT进行实例化// 模板Container用另一个类型参数T相关类型进行实例化vectorContaineroptionalT mData;
}// 模板方法定义
// 只需更新template参数列表其他部分不变包括方法前的类型限定例如
templatetypename T,templatetypename E, typename Allocator std::allocatorE Container std::vector
optional GridT, Container::at(int x, int y) {...}// 实例化和其他参数类型模板相同注意区分template template参数只能提供模板名
// Grid模板第二个参数Container是模板类型实例化时需要提供vector/deque模板名
// 不能是vectorint或dequeint这些是具体的类型名
Gridint, vector grid1;
Gridint, deque grid2;// template template参数可多层嵌套纯属好奇心驱动的尝试
templatetypename U, // 类型参数U// GridType的模板类型templatetypename T, templatetypename E, typename Allocator std::allocatorE class Container std::vectorclass GridType // 类型参数GridType
class Foo {};
// 匿名类型参数 和 匿名非类型参数都有默认值
// 貌似提供具体的默认值没有意义定义中用不到所以才匿名默认值也不会被引用
// 只有使用trait提供编译时的动态值应用SFINAE规则控制模板在符合条件时生成参见下面的示例。
templatetypename int, size_t 12
struct funcAnonymousDefault { };// 匿名模板参数编译期默认值
// 函数模板比较两个值是否相等只有两个值的类型相同时才能实例化这个模板
// typename enable_if is_same_vT, U ::type 匿名参数默认值为enable_if::type
// 注意要用enable_if::type如果没有type则无法应用SFINAE因为enable_if总是一种类型
// 错误typename enable_if is_same_vT, U 末尾缺少::type
// enable_ifarg1, arg2void
// 1如果arg1为true则enable_if::type值为arg2
// 2如果arg1为false则enable_if::type值为空导致模板语法不合规SFINAE阻止模板实例化
templatetypename T, typename U,typename enable_if is_same_vT, U ::type
bool isSameValue(T t, U u) {return t u;
}int a 3;
int b 3;
double b 3; // 编译错误参见下面错误信息cout is same? : isSameValue(a, b) endl;
// 输出结果
// is same? : 1// 编译错误信息
error: no matching function for call to ‘isSameValue(int, int)’23 | cout is same? : isSameValue(a, b) endl;| ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
note: candidate: ‘templateclass T, class U, class bool isSameValue(T, U)’15 | bool isSameValue(T t, U u) {| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
note: template argument deduction/substitution failed:
error: no type named ‘type’ in ‘struct std::enable_iffalse, void’13 | typename enable_if !is_same_vT, U ::type| ^~~~~~~~CTADclass template argument deduction自动推导类型参数 1函数模板天生支持类型推导。 2在较新版本c中类模板支持类型推导。需要构造函数中使用模板参数在初始化过程中可以推断类型和值参数。 如果模板参数在初始化过程中使用不到则无法完成类型推导。 3通过辅助模板函数在内部实例化模板类支持类型自动推导。 4特殊unique_ptrshared_ptr不支持类型推导需要用make_unique() make_shared()。 原因传入T*时编译器无法确定是类型T还是T[ ]。 5自定义推导规则可以自定义推导规则规避上面的歧义。 1必须定义在类定义外面。 2必须和类定义在同一个namespace。 3可选使用explicit关键字规则和应用在构造函数上一样。 6函数模板中返回类型不能自动推导。可让编译器推导部分参数
// 自定义推导规则
templatetypename T
struct DeductionRule {explicit DeductionRule(T t) {cout DeductionRule: T typeid(T).name() endl;}templatetypename IterDeductionRule(Iter iter) {}
};// 自定义规则语法构造函数 - 实例化类型;
DeductionRule(int) - DeductionRuledouble;
DeductionRule(const char*) - DeductionRulestring;templatetypename T
DeductionRule(Iter) - DeductionRuletypename iterator_traitsIter::value_type;// Output: 无自定义推导规则
// DeductionRule: Ti
// DeductionRule: TPKc// Output: 添加自定义推导规则后
// DeductionRule: Td
// DeductionRule: TNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE// 部分参数推导
templatetypename R, typename T, typename S
R func(T t, S s);// 以下2种调用方式等效
// 第二种省略了部分类型参数由编译器自动推导返回类型需明确指出
auto ret funclong, int, int(1, 2);
auto ret funclong(1, 2);
auto ret func(1, 2); // compilation error// 不能自动推导的类型参数通过提供默认值可以使调用时省略全部参数
// 本质上部分由编译器推导部分使用默认值都不需要手动指定
templatetypename Rlong, typename T, typename S
R func(T t, S s);
auto ret func(1, 2);模板特化全特化、偏特化 1类模板支持全特化、偏特化 2函数模板只能全特化 1函数有重载机制本质上根据不提供的类型提供不同的实现。和模板机制类似。 2在函数重载解析时函数模板不参与重载解析。 3函数模板特化不常用可能遇到非“预期”行为。模板特化和函数重载可能误用。 3特化语法 1在模板参数列表template中去掉特化的类型/非类型参数。因为这个参数已经确定不再需要占位符“变量” 在全特化时只保留template里面没有任何参数。 2类似模板实例化的语法在类名称或者函数名称后增加参数列表列出所有类型/非类型参数。 3一种“半实例化”状态template告诉编译器这是一个模板所有参数都在类定义中类名后面列出。 偏部分特化 ---- 偏/部分 实例化
template typename T, typename S
struct TempClass {TempClass(T t, S s) {cout basic temp class\n;}
};// 类模板偏特化用int特化第二个参数S
template typename T
struct TempClassT, int {TempClass(T t, int s) {cout specialize S\n;}
};
// 类模板偏特化用int特化第一个参数T
template typename S
struct TempClassint, S {TempClass() default;TempClass(int t, S s) {cout specialize T\n;}
};
// 类模板全特化
template
struct TempClassbool, bool {TempClass(bool a, bool b) {cout TempClassbool, bool\n;}
};TempClass temp1 {1.0, 2.0};
TempClass temp2 {1, 2.0};
TempClass temp3 {1.0, 2};
TempClass temp4 {false, true};// Output:
// basic template class
// TempClassint, S
// TempClassT, int
// TempClassbool, bool// 非类型参数特化
// 语法和类型参数特化一样可用于模板递归中作为递归结束条件
templateint i
struct TempClass2 {TempClass2() {cout TempClass2: basic template, i i endl;}
};template
struct TempClass210 {TempClass2() {cout TempClass2: specialized template for i10 endl;}
};TempClass2666 temp2_1;
TempClass210 temp2_2;// Output:
// TempClass2: basic template, i666
// TempClass2: specialized template for i10// 函数模板全特化
templatetypename T, typename S
void TempFunc(T t, S s) {cout TempFunc(T t, S s)\n;
}template
void TempFuncdouble, double(double t, double s) {cout TempFuncdouble, double(double t, double s)\n;
}// 实例化函数模板并调用
TempFunc(1, 2);
TempFunc(3.0, 4);
TempFunc(5.0, 6.0);// Output:
// TempFunc(T t, S s)
// TempFunc(T t, S s)
// TempFuncdouble, double(double t, double s)模板继承 友元 friend类模板的友元模板函数和友元模板类 关键operator后面的 T
// 前向声明
templatetypename T class Grid;// operator 声明
// 运算符用到了模板类Grid也要定义为模板templatetypename T
// 其中用到的类型都为模板类型GridT
templatetypename T
GridT operator (const GridT left, const GridT right);// 1. friend关键字声明友元。
// 2. operator后面T告诉编译器此operator是模板。
// 3. 在Grid模板内部使用Grid或GridT是等效的CLion验证。
templatetypename T
class Grid {
public:friend GridT operator T (const Grid left, const Grid right);
};// android: StrongPointer.h
templatetypename T
class sp {// ...
private:// 把sp自身和wp类声明为sp类的友元// sp和wp都是模板类friend关键字挨着class在class前面位于template之后templatetypename Y friend class sp;templatetypename Y friend class wp;
}函数模板返回类型和简化的函数模板语法 如果让编译器自动推导函数返回类型可使用以下几种方式 1auto // 去掉const和 2decltype(auto) // 不会去掉const和 3decltype( func() ) 4auto add(T t, S s) - decltype(ts)
// Error在前面decltype使用t和s时尚未定义
templatetypename T, typename S
decltype(t s) add(const T t, const S s)
{ return ts; }templatetypename T, typename S
auto add(const T t, const S s) - decltype(ts)
{ return ts; }简化的函数模板 1所有类型都用auto或const auto省略了templatetypename …声明。 2使用auto是编译器语法糖效果和使用templatetypename…声明一致。 3局限性 1使用auto的类型每个都不同如果需要指定多个入参为同一种类型需要使用template的方式声明。 局限性 2 因为auto没有类型名在函数体内无法直接使用对应的类型可使用decltype。
templatetypename T, typename S
decltype(auto) func(const T t, contst S s) { return t s;
}decltype(auto) func(const auto t, const auto s) { return t s;
}c20 concept 1concept由constraints-expression约束表达式构成。 2concept表达式concept expression应用已有concept 3constraints-expression组成 1一个简单的常量表达式返回bool值。 2一种新的特殊的常量表达式require表达式。 4require表达式由requirement构成 5requirement分为4种简单、类型、复合、嵌套。 6concept repression可使用或||组合使用。
// concept定义语法
templateparameter-list
concept concept-name constraints-expressions;// concept表达式
// 应用已有的概念例如IncrementableT, convertible_tobool
// 类似于调用已定义函数func(arg);
concept-nameargument-list// 约束表达式
templatetypename T
concept C sizeof(T) 4;// require表达式定义语法
requires (parameter-list) { requirements; }// requirement分为4种
// 1. simple requirement 不以requires开头相对嵌套requirement来说
// 可以是任意表达式不求值只验证编译通过验证语法和语义功能
templatetypename T
concept Incremental requires(T x) {x;x;
}// 2. type requirement
templatetypename T
concept C requires {typename T::value_type; // 验证T是否有类型value_typetypename SomeTemplateT; // 是否可以用T实例化SomeTemplate
}// 3. 复合 requirement compound requirement
// 验证不会抛出异常或者返回某种类型
// noexcept, 或-type-constraint可选的可验证某一种或同时验证
// { }是必须的即使一个语句也需要有。
{ expression } noexcept - type-constraint;templatetypename T
concept C requires(const T x, const T y) {{ x.swap(y) } noexcept; // noecept验证时{}不能省略{ x.size() } - convertible_to(size_t); // 验证返回值时一个语句时{}也不可省略{ xy } - convertible_tobool; // 不可省略{}
}// 4. 嵌套 requirement
templatetypename T
concept C requires (T t) {// 这里不能省略requires只用sizeof(T) 4是不行的不会实际校验感觉requires类似assertrequires sizeof(T) 4;
// sizeof(T) 4; // 错误可编译通过逻辑不对t;t;
}// 5. 组合概念表达式不是-不是-不是requirementcombined CONCEPT expression
// 使用||组合
templatetypename T
concept MyConcept IncrementableT DecrementableT; 模板递归 可变参数模板 1 typename… Tn 表示0个或多个参数。 2…展开其左侧的‘表达式’根据参数个数重复多次用逗号分隔。 3…前后的空格可选。 4可变参数没有直接的遍历方式只能通过模板递归遍历。
templatetypename... Tn
class Temp {...}// 可变参数函数模板 // typename… Tn声明可变类型个数 // Tn… args声明可变参数个数 // args…使用可变参数 // 使用完美转发perfect forward避免参数复制和使用字面量 // 使用确定类型参数T1和可变参数结合的方式递归分离、解析可变参数
void handleValue(int v) { cout int: v endl; }
void handleValue(double v) { }
void handleValue(string_view v) { }// 递归终止case
void processValues() { }templatetypename T1, typename... Tn
void processValues(T1 arg1, Tn... args) {handleValue(arg1);processValues(args...);
}templatetypename T1, typename... Tn
void processValues(T1 arg1, Tn... args) {handleValue(std::forwardT1(arg1));processValues(std::forwardTn(args)...); // 注意此处...在每个参数上执行forward
}// sizeof...操作符和sizeof是不同的操作符
int count { sizeof...(args) }使用可变参数模板实现Mixin模板类
struct Base1 {int mValue;Base1(int i): mValue(i) { }void func1() {cout Base1: value mValue endl;}
};struct Base2 {int mValue;Base2(int i): mValue(i) { }void func2() {cout Base2: value mValue endl;}
};templatetypename... Cn // 1. 声明可变参数typename... Cn
struct Mixin: public Cn... { // 2. 继承可变参数public Cn...Mixin(const Cn... classes): Cn {classes} ... {} // 3. 可变参数作为函数参数Cn... clsvirtual ~Mixin() default; // 以及初始化可变参数成员变量Cn{classes}...
};// 调用
MixinBase1, Base2 mix { Base1{123}, Base2{456}}; // 初始化方式1auto b1 Base1{123};
auto b2 Base2{456};
MixinBase1, Base2 mix {b1, b2}; // 初始化方式2mix.func1();
mix.func2();// output:
// Base1: value123
// Base2: value456constexpr if折叠表达式folld expressions元编程
// 模板递归计算阶乘
templatesize_t n
struct Factorial {constexpr static int value n * Factorialn -1::value;
};template
struct Factorial0 {constexpr static int value 1;
};cout fact: Factorial1000::value endl;// 模板递归循环
templatesize_t n
struct Loop {templatetypename Funcstatic void run(Func func) {// Loop::run和func()的执行顺序决定是正序循环还是逆序循环Loopn-1::run(func);func(n);}
};template
struct Loop0 {templatetypename Funcstatic void run(Func func) {}
};Loop5::run([](int i){cout run: i endl;
});traits在一个声明中多次使用template的场景 1模板类的模板方法定义 2模板的template template参数
// 顺序并列使用2个template关键字
templatetypename ClassArgType
templatetypename MethodArgType
void TempClassArgType::func(MethodArgType data) { ... }// template中嵌套template
// 可嵌套多层参见上面template template参数中的例子
templatetypename T,templatetypename E, typename AllocatorE std::allocatorE Container std::vector
class Grid { ... }