C++ 模板支持 - 2022.1 简体中文

Versal ACAP AI 引擎编程环境 用户指南 (UG1076)

Document ID
UG1076
Release Date
2022-05-25
Version
2022.1 简体中文

在 C++ 中,模板是强大的工具。只需将数据类型作为参数来传递,则无需重写编码也可支持不同数据类型。模板在编译时展开,就像宏一样。区别在于,编译器会在模板展开之前执行类型检查。源代码包含模板函数和类定义,但编译的代码可包含相同函数或类的多个副本。类型参数、非类型参数、默认实参、标量实参和模板参数均可传递给模板,编译器会在其中对函数或类进行相应的例化。

  • 支持常用 C++ 模板功能特性。
  • 内核之间受支持的数据类型 (T) 和连接类型:
    • 数据类型 (T):int8uint8int16uint16cint16int32uint32cint32int64uint64floatcfloat
      重要: 在模板串流连接中,不支持 acc48cacc48 数据类型。
    • 函数参数类型:input_window<T>output_window<T>input_stream<T>output_stream<T>
  • 编译器不支持预编译模板内核报头。

函数模板

函数模板源代码定义了可用于不同数据类型的泛型函数。函数模板示例:

// add.h
template<typename ELEMENT_TYPE, int FACTOR, size_t NUM_SAMPLES> void add(input_window<ELEMENT_TYPE>* in, 
 output_window<ELEMENT_TYPE>* out);
// add.cpp
template<typename ELEMENT_TYPE, int FACTOR, size_t NUM_SAMPLES> void add(input_window<ELEMENT_TYPE>* in, 
 output_window<ELEMENT_TYPE>* out)
{
    for (int i=0; i<NUM_SAMPLES; i++)
    {
        ELEMENT_TYPE value = window_readincr(in);
        value += FACTOR;
        window_writeincr(out, value);
    }
}
// graph.h
mygraph()
{
    k[0] = kernel::create(add<int32, 6, 8>);
    k[1] = kernel::create(add<int16, 3, 8>);
    for (int i=0; i<NUM_KERNELS; i++)
    {
        runtime<ratio>(k[i]) = 0.3;
        source(k[i]) = "src/add.cpp";
    }

    connect<window<32>>(in[0], k[0].in[0]);
    connect<window<32>>(k[0].out[0], out[0]);

    connect<window<16>>(in[1], k[1].in[0]);
    connect<window<16>>(k[1].out[0], out[1]);
}

其中:

  • add.h 用于定义模板 add() 函数。
  • add.cpp 用于定义 add() 模板函数的代码。
  • graph.hmygraph 类中使用 add() 模板函数。

类模板

正如函数模板一样,如果类定义的对象与特定数据类型无关,那么类模板也很有用。类模板示例:

// fir.h
...
template<size_t NUM_COEFFS, typename ELEMENT_TYPE> class FIR
{
private:
    ELEMENT_TYPE (&coeffs)[NUM_COEFFS];
    ELEMENT_TYPE tapDelayLine[NUM_COEFFS];
    uint32 numSamples;

public:
    FIR(ELEMENT_TYPE(&coefficients)[NUM_COEFFS], uint32 samples);

    void filter(input_window<ELEMENT_TYPE>* in, output_window<ELEMENT_TYPE>* out);

    //user needs to write this function to register necessary info
    static void registerKernelClass()
    {
        REGISTER_FUNCTION(FIR::filter);
        REGISTER_PARAMETER(coeffs);
    }
};
// fir.cpp
...
template<size_t NUM_COEFFS, typename ELEMENT_TYPE> FIR<NUM_COEFFS, ELEMENT_TYPE>::FIR(ELEMENT_TYPE(&coefficients)[NUM_COEFFS], uint32 samples):coeffs(coefficients)
{
    ...
}

template<size_t NUM_COEFFS, typename ELEMENT_TYPE> void FIR<NUM_COEFFS, ELEMENT_TYPE>::filter(input_window<ELEMENT_TYPE>* in, output_window<ELEMENT_TYPE>* out)
{
    ...
}
// graph.h
...
mygraph()
{
    k1 = kernel::create_object<FIR<12, int32>>(std::vector<int>({ 180, 89, -80, -391, -720, -834, -478, 505, 2063, 3896, 5535, 6504 }), 8);
    runtime<ratio>(k1) = 0.1;
    source(k1) = "src/fir.cpp";
    headers(k1) = { "src/fir.h" };

    k2 = kernel::create_object<FIR<15, int32>>(std::vector<int>({ -21, -249, 319, -78, -511, 977, -610, -844, 2574, -2754, -1066, 18539, 0, 0, 0 }), 8);
    runtime<ratio>(k2) = 0.1;
    source(k2) = "src/fir.cpp";
    headers(k2) = { "src/fir.h" };
    ...
}

其中:

  • fir.h 用于定义声明类 FIR 的类模板。
  • fir.cpp 包含类 FIR 的实现和类 FIR 成员函数 filter 的实现。
  • graph.h 演示了 mygraph 类中的模板类 FIR 的例化。