Template parameter matching for templates

1. The template is used as the parameter of the template

In the actual project, there is a situation that requires the use of callback functions to process specific data. Here, non-type template parameters need to be processed. After the processing is completed, I want to write about other situations. In this callback function, it is necessary to deal with the template parameter of the template in different situations. What is the template parameter of the template? It is the case where the parameter of the template is a template. It has been analyzed before, so I won’t go into details. This time, I just use a practical example to illustrate how to use it.

2. Routine

This practical example is to pass the internal parameter pointer back to the application through the callback function reference, and the application will handle the related operations. Then there is a problem here. In the callback function, it is a template parameter. How to deal with it? Look at the basic version of it, that is, template parameters that don't use templates:

template <typename T, size_t N = 100> struct Data final {
    
    
 ......
};
std::optional<size_t> Add(std::function<void(Data<T> *&, size_t)> fn) {
    
    
......
}

In this case, you can directly write a similar function in the application layer and bind it to std::function. However, this method is less flexible, so several versions have been modified:

#include <iostream>
#include <string>
using namespace std;

//常量定义,用于模板参数
constexpr size_t num = 100;

//三种不同的模板类定义,供做模板参数
template <typename T>
struct SData final {
    
    

  std::array<T, 100> Buf = {
    
    0};
};
template <typename T, typename N>
class SSData {
    
    

   //std::array<T, N> Buf = {0};//此处N为非常数,关闭
};
template <typename T, size_t N = 100>
class SoData {
    
    

  std::array<T, N> Buf = {
    
    0};
};

//三个匹配的调用函数
std::optional<size_t>
getData(SData<A> *&sd,size_t size = 100) {
    
    
  std::cout << "this is test" << std::endl;
}
std::optional<size_t>
getData2(SSData<A, size_t> *&sd,size_t size = 100) {
    
    
  std::cout << "this is test2" << std::endl;
}
// num can ignore
std::optional<size_t>
getData3(SoData<A, num> *&sd,size_t size = 100) {
    
    
  std::cout << "this is test3" << std::endl;
}

//三个模板函数
template <typename T, template <typename N> typename Con>
using Fn = std::function<std::optional<size_t>(Con<T> *&, size_t)>;

template <typename T, typename P,
          template <typename N, typename U> typename Con>
using Fn2 = std::function<std::optional<size_t>(Con<T, P> *&, size_t)>;
template <typename T, size_t P,
          template <typename N, size_t U = 100> typename Con>
using Fn3 = std::function<std::optional<size_t>(Con<T, P> *&, size_t)>;

//模板参数类,形式上用
struct A {
    
    
 ......
};
int main() {
    
    

  Fn<A, SData> fn = getData;
  Fn2<A, size_t, SSData> fn2 = getData2;
  Fn3<A, num, SoData> fn3 = getData3; num can ignore

  SData<A> *smd =new SData<A>;
  SSData<A, size_t> *ssmd =new SSData<A, size_t>;
  SoData<A, num> *somd =new SoData<A, num>; num can ignore

  fn(smd, 100);
  fn2(ssmd, 100);
  fn3(somd, 100);

  return 0;
}

The main problems and solutions encountered this time:
1. The problem of writing the wrong name. This kind of low-level mistake is very troublesome. It is mainly due to the inertia of thinking. It is often found out after a break.
2. Due to the use of tools, sometimes square brackets are automatically introduced, so that template parameters (especially when defining variables) are wrapped in square brackets (should be angle brackets), causing problems.
3. If you encounter template problems that are not easy to solve in actual situations, you can push back from instantiation to make it easier to understand and find problems.
4. Pay attention to compilation warnings and error prompts, especially when assigning values ​​to the Fn series this time, the error prompts are very accurate.
5. Start from the basics, don't make it too big at the beginning, if it has already been made too big, you can simplify the model, and push back after success.
The most important thing is that the template parameters of the template are actually similar to bamboo shoots. The nesting of the inner layer depends on the external template parameters. The external template parameters are equivalent to the implementation of the internal template parameters, which is very important. In other words, you cannot directly manipulate the template parameters of the next layer at the outermost layer. This is very important, remember. In addition, when declaring template parameters, the parameter definitions between layers have the same status, that is to say, the template parameters of the previous layer cannot be used by the next layer, otherwise "Declaration of 'T' shadows template parameter" will be reported. The upper-level definition covers the lower-level definition, and anyone who has studied C++ knows the reason.
To explain, operating the internal template parameters in a disguised form by some means is not a direct operation, and the direct operation here is direct instantiation.
If you have time, you can write it as an implementation of a variable parameter template, and it is estimated that the adaptability will be better.

3. Summary

Originally, I wanted to simplify the operation in engineering practice, and at the same time, I could use decltype to handle the return value of the callback function, but the result was counterproductive. The matching of this template made the work more complicated. However, it is also a blessing to take this opportunity to have a stronger understanding of template matching.
The saying that true knowledge comes from practice is really very reasonable.

Guess you like

Origin blog.csdn.net/fpcc/article/details/132240458