Advanced C++ Features

The following section introduces the advanced C++ features (templates and constexpr) supported by devices.

Templates

Templates are classified into the following two types: function template and class template.
  • Function template
    Template features are applied to functions, including non-type template parameters, type template parameters, and variadic template parameters. Both non-type template parameters and type template parameters can have default values.
    • Non-type template parameters
      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();                // Error: The first template parameter does not have a default argument.
          *out = func<true>();          // OK, flag1 == true, flag2 == true, value: 10
          *out = func<false, false>();  // OK, flag1 == false, flag2 == false, value: 30
      }
    • Type template parameters
      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);                     // Error: The first template parameter does not have a default argument.
          *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
      }
    • Variadic template parameters
      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. The parameter list includes int, short, and long. The value is 70.
      }
  • Class template
    Template features are applied to classes, including non-type template parameters, type template parameters, and variadic template parameters. Both non-type template parameters and type template parameters can have default values.
    • Non-type template parameters
      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;                      // Error: The first template parameter does not have a default argument.
          A<true> a2;                // OK, flag1 == true, flag2 == true
          A<false, false> a3;        // OK, flag1 == false, flag2 == false
          *out = a2.func();          // The value is 10.
          *(out + 1) = a3.func();    // The value is 30.
      }
    • Type template parameters
      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;                         // Error: The first template parameter does not have a default argument.
          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);
      }
    • Variadic template parameters
      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 has three parameters.
          *out = a.func_entry(200, 300);      // Error: Parameter mismatch.
          *out = a.func_entry(200, 300, 400); // The value is 1000.
          *out = a.func_entry(200, 300, 400, 500); // Error: Parameter mismatch.
      }

constexpr

A constexpr expression is an expression whose value is constant and is computed at compile time. A variable declared as constexpr must be a const variable and must be initialized using a constant expression.

constexprint mf = 20;  //20 is a constant expression.
constexprint limit = mf + 1; // mf + 1 is a constant expression.
constexprint sz = size (); // The declaration statement is correct only when size is a constexpr function.

In an if condition statement, the value of the condition must be a constant expression that can be converted to the bool type based on the context. The expressions and restrictions are as follows:

  • Modifying an expression
    template<typename T>
    auto inline __aicore__ get_value(T t)
    {
        if constexpr (std::is_pointer_v<T>)
            return *t; // For T = int*, the return type is int.
        else
            return t;  // For T = int, the return type is int.
    }
    
    void inline __aicore__  f(__gm__ int* Out)
    {
        if constexpr (sizeof(int) == 3)
            *Out = 1;      // The code is discarded during compilation.
        else
            *Out = 2;}
  • Modifying a bool value
    void inline __aicore__  f(__gm__ int* Out)
    {
        if constexpr (true)
            *Out = 1;
        else
            *Out = 2;      // The code is discarded during compilation.
    }
  • Implementation in a class
    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 is a compilation constant. Compilation normal.
               res = 100;
        else res = 200;
    
        ConstClass t2;
        if constexpr (t2.c > 0) // t2 is not a compilation constant. Compilation failed.
               res = 100;
        else res = 200;
    
        return res;
    }
  • Selection syntax check

    The discarded statements also go through a complete code check. The code with syntax errors is not simply ignored because it is discarded.

    void inline __aicore__  f()
    {
        if constexpr (false) // This code segment will not be compiled.
        {
           int i = 0;
           int *p = i; // Syntax error. As a result, the compilation fails.
        }
    }