#include <iostream> template <typename T> class Test { private: T value; public: Test(); Test(T valueOfUser); T getValue(); T setValue(T valueOfUser); }; template<typename TT> Test<TT>::Test():value(0) {} template<typename VOOBSHE_DRUGOE_NAZVANIE> Test<VOOBSHE_DRUGOE_NAZVANIE>::Test(VOOBSHE_DRUGOE_NAZVANIE valueOfUser): value(valueOfUser) {} template<typename T> T Test<T>::getValue() { return value; }; template<typename T> T Test<T>::setValue(T valueOfUser) { value = valueOfUser; } int main() { Test<int> test(1); std::cout << test.getValue(); return 0; } 

I would like to know in more detail and step by step how the compiler learns what type you need to define TT , VOOBSHE_DRUGOE_NAZVANIE , T , if the method of "recognition" does not depend on the name? Just when you start to use header files and declare a method inside a class template, and to define this method somewhere in .cpp , the compiler will not understand what type to install TT , VOOBSHE_DRUGOE_NAZVANIE , T , if I created a class in some other .cpp , I need like something sly. Therefore, I wanted to look deeper.

  • one
    Templates should usually be defined in a header file. TT and VOOBSHE_DRUGOE_NAZVANIE are alternative identifiers for the template parameter T (using different identifiers for the same parameter is a bad idea) and is explicitly specified in the line Test<int> - VTT at
  • The question is not clear. A class template (and its method templates) have one type parameter. It is enough for the compiler to know this, and to know what the corresponding argument is equal to. And what it is called in each separate context does not matter. - AnT

1 answer 1

Suppose somewhere in the code you have the following instruction

 a.setValue(42); 

At the same time, the compiler knows that the expression a is of type Test<int> . For example, earlier a was declared as a reference Test<int> &a or as an object Test<int> a .

Please note that it is quite possible that up to this point the compiler has not yet had to look for the definition of the Test pattern. For example, if Π° declared as a link, then such a link can be simply declared as

 template <typename> class Test; void foo(Test<int> &a) { ... 

That is, to declare a link (or pointer) to Test<int> compiler does not need a full definition of the Test pattern at all. All that is needed is the β€œmention” (declaration) of the fact that Test is some sort of class template with one type parameter.

But as soon as the compiler came across an operator application . to a in

 a.setValue(42); 

the compiler already needs to instantiate Test<int> and be sure to find the complete definition of the Test template. From the definition of Test<int> compiler will also figure out what setValue .

So, the compiler will search for the definition of the "main" template of the class Test<ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ Ρ‚ΠΈΠΏΠΎΠ²ΠΎΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€> . Having found this definition, it will also search for its explicit or partial specializations (for example, Test<int> ).

In your example, the compiler will only find the definition of the β€œmain” template.

 template <typename T> class Test { ... T setValue(T valueOfUser); }; 

That is, the compiler will come to the conclusion that type a is this particular template with T == int .

Either from the main template, or from a more suitable specialization (if one was found), he learns what setValue . In your example, this is a template class method. At this point, the compiler recognizes the types, the number of method parameters, and the type of its return value.

It will then search for a template definition for the Test<ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ Ρ‚ΠΈΠΏΠΎΠ²ΠΎΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€>::setValue method Test<ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ Ρ‚ΠΈΠΏΠΎΠ²ΠΎΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€>::setValue . Suppose the definition was found and looks like

 template <typename VASYA> VASYA Test<VASYA>::setValue(VASYA valueOfUser) { value = valueOfUser; } 

Comparing the original Test<int> with Test<VASYA> compiler will come to the conclusion that VASYA == int . The fact that the parameter was called T in the definition of the class template and the corresponding parameter in the definition of the method template is called VASYA doesn’t affect anything at all and doesn’t appear in this process.

In addition, the compiler will search for an explicit specialization Test<int>::setValue . If not found, the compiler will use the "main" method template with VASYA == int to instantiate this method. If there is an explicit specialization, the compiler will use the specialization.

That's all.


What kind of "and already somewhere in .cpp determine this method" you are talking about is not clear. Template definitions should be placed in header files. In the .cpp file, you can place only [already] non-template definitions - definitions of explicit specializations, for example.

  • For example, I have the header file "Test.h", in which there is an announcement of the template class Test and within which there are declarations of methods and constructors, and now in Test.cpp I define all this, naturally with a template . I connect in Test.cpp Test.h and in main.cpp also connect Test.h I create in main.cpp for example Test<int> a and somewhere I write a.getValue() ; I get an error, because in Test.cpp compiler cannot determine my T , TT @AnT - Kaznachei 6:29 pm
  • I just clarify this, I agree that I wrote incomprehensibly, and I received the answer from you, thank you. @AnT - Kaznachei pm
  • @Kaznachei: Well, as you have already been told, you can’t do that. Method definitions should also be in Test.h , and you probably won't need Test.cpp at all (unless you have explicit specializations). And the error you get in your version has nothing to do with T and TT . Why did you decide that it happens because "the compiler cannot determine my T, TT in any way" - I do not know. - AnT 6:33 pm