0

I'm really confused by templates. If I have a template class and I pass it as an argument to a function, consider the following :

template <class T> class Class
{

};

So I want to make a function that takes Class as an argument, so why the following won't be enough :

void func(Class<T> obj)
{

}

and I'll have to do :

template <class T> void func(Class<T> obj)
{

}

also, say I take 2 arguments of 2 template classes, consider the following :

template <class T> class ClassA
{

};
template <class T> class ClassB
{

};

and I have a function that takes 2 arguments of type ClassA and ClassB, what is the difference between writing :

template <class T> void func(ClassA<T> obj1, ClassB<T> obj2)
{

}

to

template <class T, class ClassB> void func(ClassA<T> obj1, ClassB obj2)
{

}

because both works.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
Tugal.44
  • 153
  • 4
  • 13

2 Answers2

3

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.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
1

A class-template is not a class, neither is a function-template a function, they are just templates for making them.

Thus, it's no wonder you cannot use a template where a type respective function is needed.

The names of template-arguments have the same importance as the names of function-arguments outside their scopes:
None whatsoever. In their scope, they naturally shadow names from outer scopes.

Thus, the token T likely does not denote anything where you tried to declare (and in addition define) your function.
And ClassB in a template with that as template-argument-name, denotes the teplate-argument and not some outer-scope class which might happen to exist as well.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118