昇腾社区首页
中文
注册

支持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变量,而且必须用常量表达式初始化。

constexprint mf = 20;  //20是常量表达式
constexprint limit = mf + 1; // mf + 1是常量表达式
constexprint 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;   // 语法错误,导致编译失败
        }
    }