---
title: 支持C++高级特性
description: "下文对设备侧支持的C++高级特性（template模板和constexpr表达式）进行介绍。"
url: https://www.hiascend.com/document/detail/zh/canncommercial/latest/compiler/BishengCompiler/atlas_bisheng_10_0007.html
sourcePath: /source/zh/canncommercial/900/compiler/BishengCompiler/atlas_bisheng_10_0007.html
indexId: 6c00485c516eed943807551af03fe72b4f081efca38a689e3d8386576fcd531181
---
# 支持C++高级特性

下文对设备侧支持的C++高级特性（template模板和constexpr表达式）进行介绍。

#### template模板

template模板特性分为函数模板和类模板两种。- 函数模板
  将模板特性作用在函数上，主要分为无类型模板参数、类型模板参数和变长模板参数，对于无类型和类型模板参数，又有有无默认值的区分。
  - 无类型模板参数

```
template<bool flag1, bool flag2 = true>
uint32_t inline __aicore__ func() {
return flag1 ? 10 : (flag2 ? 20 : 30);
}
void inline __aicore__ foo(__gm__ uint32_t * out) {
*out = func();                // 错误：第一个模板参数没有默认实参
*out = func<true>();          // OK， flag1 == true， flag2 == true，值为10
*out = func<false, false>();  // OK， flag1 == false， flag2 == false，值为30
}
```


  - 类型模板参数

```
template<typename T1, typename T2 = uint8_t>
T1 inline __aicore__ func(T2 right) {
return 10 + right;
}
void inline __aicore__ foo(__gm__ uint32_t * out) {
*out = func(10);                       // 错误：第一个模板参数没有默认实参
*out = func<uint32_t>(10);  // OK，T1：uint32_t， T2：uint8_t
*out = func<uint32_t, uint16_t>(10);   // OK，T1：uint32_t， T2：uint16_t
}
```


  - 变长模板参数

```
uint32_t inline __aicore__ func() {
return 10;
}
template<typename T, typename ...Ts>
uint32_t inline __aicore__ func(T first, Ts... last) {
return first + func(last...);
}
void inline __aicore__ foo(__gm__ uint32_t * out) {
*out = func((int)10, (short)20, (long)30);   // OK，参数列表分别为int，short，long， 值为70
}
```


- 类模板
  将模板特性作用在类上，主要分为无类型模板参数、类型模板参数和变长模板参数，针对无类型和类型模板参数，又有有无默认值的区分。
  - 无类型模板参数

```
template<bool flag1, bool flag2 = true>
class A {
public:
uint8_t inline __aicore__ func() {
return flag1 ? 10 : (flag2 ? 20 : 30);
}
};
void inline __aicore__ foo(__gm__ uint8_t * out) {
A a1;                      // 错误：第一个模板参数没有默认实参
A<true> a2;                // OK， flag1 == true， flag2 == true
A<false, false> a3;        // OK， flag1 == false，flag2 == false
*out = a2.func();          // 值为10
*(out + 1) = a3.func();    // 值为30
}
```


  - 类型模板参数

```
template<typename T1, typename T2 = uint8_t>
class A {
public:
T1 inline __aicore__ func(T2 right) {
return 10 + right;
}
};
void inline __aicore__ foo(__gm__ uint8_t * out) {
A a1;                         // 错误：第一个模板参数没有默认实参
A<uint32_t> a2;               // OK， T1：uint32_t， T2：uint8_t
A<uint32_t, uint16_t> a3;     // OK， T1：uint32_t， T2：uint16_t
*out = a2.func(20);
*(out+1) = a3.func(20);
}
```


  - 变长模板参数

```
template<typename ...Ts>
class A {
public:
uint32_t inline __aicore__ func() {
return 100;
}
template<typename T, typename ...TTs>
uint32_t inline __aicore__ func(T first, TTs... last) {
return first + func(last...);
}
uint32_t inline __aicore__ func_entry(Ts... ts) {
return func(ts...);
}
};
void inline __aicore__ foo(__gm__ uint8_t * out) {
A<int, long, short> a;              // OK， func_entry参数列表为3个
*out = a.func_entry(200, 300);      // 错误：参数不匹配
*out = a.func_entry(200, 300, 400); // 值为1000
*out = a.func_entry(200, 300, 400, 500); // 错误：参数不匹配
}
```


#### constexpr表达式

constexpr表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。声明为constexpr的变量一定是一个const变量，而且必须用常量表达式初始化。

```
constexpr int mf = 20;  // 20是常量表达式
constexpr int limit = mf + 1; // mf + 1是常量表达式
constexpr int sz = size(); // 之后当size是一个constexpr函数时才是一条正确的声明语句
```

在if条件语句中，条件的值必须是按语境可以转换到bool类型的常量表达式，有如下表达和约束：

- 修饰表达式

```
template<typename T>
auto inline __aicore__ get_value(T t)
{
if constexpr (std::is_pointer_v<T>)
return *t; // 对 T = int* 推导返回类型为 int
else
return t;  // 对 T = int 推导返回类型为 int
}
void inline __aicore__  f(__gm__ int* Out)
{
if constexpr (sizeof(int) == 3)
*Out = 1;      // 该代码编译期被舍去
else
*Out = 2;
}
```


- 修饰bool值

```
void inline __aicore__  f(__gm__ int* Out)
{
if constexpr (true)
*Out = 1;
else
*Out = 2;      // 该代码编译期被舍去
}
```


- 类中实现

```
class ConstClass
{
public:
int a = 2;
int b = 3;
int c = a * b;
};
int inline __aicore__ f()
{
int res = 0;
constexpr ConstClass t1;
if constexpr (t1.c > 0) // t1 是编译期常量，可以正常编译
res = 100;
else res = 200;
ConstClass t2;
if constexpr (t2.c > 0) // t2 不是编译期常量，编译失败
res = 100;
else res = 200;
return res;
}
```


- 舍去分支语法检查
  被舍去的语句同样会经过完整的代码检查，语法错误的代码并不会因为被舍弃而被忽略。

```
void inline __aicore__  f()
{
if constexpr (false) // 该段代码不会被编译
{
int i = 0;
int *p = i;   // 语法错误，导致编译失败
}
}
```
