Don't get confused by the class
keyword in class ClassB
syntax within template-parameter-list. That is, the class
keyword there does not indicate an actual class (no even a class of a given name), rather, it is a name for a type that will be either deduced or specified in a template-argument-list. Alternatively, (what I prefer), you can use the typename
keyword, which better expresses its meaning:
That is:
template <class T, class ClassB> void func(ClassA<T> obj1, ClassB obj2)
is equal to:
template <typename T, typename ClassB> void func(ClassA<T> obj1, ClassB obj2)
The ClassB
name within the func
scope shadows the class ClassB
declaration. In the scope of the function this is the name of the type deduced or specified in a template-argument-list. That is, it can be literally anything:
func(ClassA<int>{}, 123); // ClassB is now deduced to be int
func(ClassA<int>{}, 3.14); // ClassB is now deduced to be double
func(ClassA<int>{}, 'A'); // ClassB is now deduced to be char
func<int, long long>(ClassA<int>{}, 5); // ClassB is specified to be long long
And an example that illustrates the shadowing:
template <class T, class ClassB> void func(ClassA<T> obj1, ClassB obj2)
{
ClassB a; // a has the deduced or specified type
::ClassB<int> b; // b has the true ClassB<int> type
}
Finally, the difference between the above declaration and the below one:
template <class T> void func(ClassA<T> obj1, ClassB<T> obj2)
is that in the latter case the func
accepts ClassA
instance and ClassB
instance with the same type argument, whereas the first declaration, as it was said, can match any type as the second one.
In the other words, in the first example, the template argument deduction mechanism for the first parameter's type is restricted to deduce only the type T
within ClassA<T>
declaration, and not restricted in any way in deducing the second parameter's type.