C + +: non inferential context of template and STD:: type_ identity

Time:2021-6-27

At first glance, this title is very mysterious, but in fact, it only involves a very simple knowledge point of CPP template derivation.

When I was working on CPP development recently, I encountered the following inference errors in compiling: Note: candidate template ignored: reduced conflicting types for parameter t (long long vs. long int). I hope it will be helpful to you.

1. Non inferential context

As we all know, the use of function template is the process of type derivation at C + + compile time. By analyzing the types of function parameters in the source code, we can infer the types of function parameters to generate the corresponding functions automatically, so as to achieve the effect of simplifying the code logic.

What about non inferential context? The type of the template does not participate in the derivation of template arguments. Instead, it uses template arguments that can be inferred elsewhere or explicitly specified.

It may be difficult to understand the above words. We can understand it by looking at the code directly.

2. Take a chestnut for example

Let’s take a look at the following simple code:

  template<typename T>

  struct TestTemplate {

  T t;

  };

  template<typename T>

  T add(TestTemplate<T>& test, T val) {

  return test.t + val;

  }

  int main() {

  TestTemplate<long> test_template{100};

  return add(test_template, 10);

  }

When compiling, the following error is reported:

  note: template argument deduction/substitution failed:

  note: deduced conflicting types for parameter ‘T’ (‘long int’ and ‘int’)

We can see that there is a wrong template inference problem through GCC compilation. In the same function, the template type T is inferred as long and int at the same time.

Let’s analyze itgameThe process of template inference.

First, the parameter test_ The type of template is testtemplate < long >, which is passed in as the first parameter of the add function. At this time, the type of T is derived as long.

Then, the type of the parameter Val is int, which is passed in as the second parameter of the add function. At this time, because 13 is int type, t is derived as int type.

Because of this, in the process of template derivation of add function, two parameters test and val participate in the derivation of template type at the same time, which leads to the above problems.

We can try to call the add function as follows: add (test)_ template, 10l)。 At this time, Val, as a parameter t, is also derived as long type, so the compilation will not report any errors.

3. Use non inferential context to solve problems

Obviously, in the above code, we hope that the compiler can automatically deduce the int type to long without annoying error reporting. Then we need to use the non inferential context to solve the problem, let the type of Val not participate in the process of type derivation, then the problem is solved.

The non inferential context of template is more complex. If necessary, please refer to the detailed explanation of cppreference. We will use the first and most common non inferential context to solve the problem mentioned above.

  The nested-name-specifier (everything to the left of the scope resolution operator ::)

To put it simply: the type of the left scope does not participate in the derivation of the template type.

So the above code is changed to the following code to avoid the original problem.

  template<typename T>

  struct TestTemplate {

  T t;

  };

  template<typename T> struct identity { typedef T type; };

  template<typename T>

  T add(TestTemplate<T>& test, typename identity<T>::type val) {

  return test.t + val;

  }

  int main() {

  TestTemplate<long> test_template{1000};

  return add(test_template, 10);

  }

Here, we add a new type identity, and use typename identity < T >:: type to avoid the type inference process of template, so that the type inference of Val directly uses the type inference result of test parameter, so the type of Val is long, and the template type inference is no longer wrong.

It is precisely because non inferential context will be used in template inference that C + + 20 provides a new trait: non inferential context

std::type_ Identity and STD:: type_ identity_ T to help us solve the above problems. Their implementation and function are consistent with the identity shown above. They all use the non inferential context of templates to avoid the compilation failure caused by different type inferences.

4. Summary

Some template inference problems in C + + are often maddening. Many times, a long string of errors given by GCC are easy to persuade Mengxin. This article talks about the template inference problems encountered by the author in the actual development, and analyzes the errors step by step. I hope you will be patient in solving the compilation problems, and be good at using the search engine( Of course, the updated C + + standard also contributes to our problem-solving Arsenal. Learning more is the right way. Daily thinking: C + + 20 is good ~ ~)

I hope you can gain something, the author’s level is limited. It is inevitable that there are misunderstandings in the writing. We welcome your discussion and advice.