[go: up one dir, main page]

100% found this document useful (1 vote)
36 views54 pages

C++ 18 Templates

Uploaded by

btech10253.19
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
36 views54 pages

C++ 18 Templates

Uploaded by

btech10253.19
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 54

Templates (C++)

Article • 10/17/2022

Templates are the basis for generic programming in C++. As a strongly-typed language,
C++ requires all variables to have a specific type, either explicitly declared by the
programmer or deduced by the compiler. However, many data structures and
algorithms look the same no matter what type they are operating on. Templates enable
you to define the operations of a class or function, and let the user specify what
concrete types those operations should work on.

Defining and using templates


A template is a construct that generates an ordinary type or function at compile time
based on arguments the user supplies for the template parameters. For example, you
can define a function template like this:

C++

template <typename T>


T minimum(const T& lhs, const T& rhs)
{
return lhs < rhs ? lhs : rhs;
}

The above code describes a template for a generic function with a single type parameter
T, whose return value and call parameters (lhs and rhs) are all of this type. You can name
a type parameter anything you like, but by convention single upper case letters are most
commonly used. T is a template parameter; the typename keyword says that this
parameter is a placeholder for a type. When the function is called, the compiler will
replace every instance of T with the concrete type argument that is either specified by
the user or deduced by the compiler. The process in which the compiler generates a
class or function from a template is referred to as template instantiation; minimum<int> is
an instantiation of the template minimum<T> .

Elsewhere, a user can declare an instance of the template that is specialized for int.
Assume that get_a() and get_b() are functions that return an int:

C++

int a = get_a();
int b = get_b();
int i = minimum<int>(a, b);
However, because this is a function template and the compiler can deduce the type of T
from the arguments a and b, you can call it just like an ordinary function:

C++

int i = minimum(a, b);

When the compiler encounters that last statement, it generates a new function in which
every occurrence of T in the template is replaced with int :

C++

int minimum(const int& lhs, const int& rhs)


{
return lhs < rhs ? lhs : rhs;
}

The rules for how the compiler performs type deduction in function templates are based
on the rules for ordinary functions. For more information, see Overload Resolution of
Function Template Calls.

Type parameters
In the minimum template above, note that the type parameter T is not qualified in any
way until it is used in the function call parameters, where the const and reference
qualifiers are added.

There is no practical limit to the number of type parameters. Separate multiple


parameters by commas:

C++

template <typename T, typename U, typename V> class Foo{};

The keyword class is equivalent to typename in this context. You can express the
previous example as:

C++

template <class T, class U, class V> class Foo{};


You can use the ellipsis operator (...) to define a template that takes an arbitrary number
of zero or more type parameters:

C++

template<typename... Arguments> class vtclass;

vtclass< > vtinstance1;


vtclass<int> vtinstance2;
vtclass<float, bool> vtinstance3;

Any built-in or user-defined type can be used as a type argument. For example, you can
use std::vector in the Standard Library to store variables of type int , double , std::string,
MyClass , const MyClass *, MyClass& , and so on. The primary restriction when using

templates is that a type argument must support any operations that are applied to the
type parameters. For example, if we call minimum using MyClass as in this example:

C++

class MyClass
{
public:
int num;
std::wstring description;
};

int main()
{
MyClass mc1 {1, L"hello"};
MyClass mc2 {2, L"goodbye"};
auto result = minimum(mc1, mc2); // Error! C2678
}

A compiler error will be generated because MyClass does not provide an overload for
the < operator.

There is no inherent requirement that the type arguments for any particular template all
belong to the same object hierarchy, although you can define a template that enforces
such a restriction. You can combine object-oriented techniques with templates; for
example, you can store a Derived* in a vector<Base*>. Note that the arguments must be
pointers

C++

vector<MyClass*> vec;
MyDerived d(3, L"back again", time(0));
vec.push_back(&d);
// or more realistically:
vector<shared_ptr<MyClass>> vec2;
vec2.push_back(make_shared<MyDerived>());

The basic requirements that std::vector and other standard library containers impose
on elements of T is that T be copy-assignable and copy-constructible.

Non-type parameters
Unlike generic types in other languages such as C# and Java, C++ templates support
non-type parameters, also called value parameters. For example, you can provide a
constant integral value to specify the length of an array, as with this example that is
similar to the std::array class in the Standard Library:

C++

template<typename T, size_t L>


class MyArray
{
T arr[L];
public:
MyArray() { ... }
};

Note the syntax in the template declaration. The size_t value is passed in as a template
argument at compile time and must be const or a constexpr expression. You use it like
this:

C++

MyArray<MyClass*, 10> arr;

Other kinds of values including pointers and references can be passed in as non-type
parameters. For example, you can pass in a pointer to a function or function object to
customize some operation inside the template code.

Type deduction for non-type template parameters


In Visual Studio 2017 and later, and in /std:c++17 mode or later, the compiler deduces
the type of a non-type template argument that's declared with auto :

C++
template <auto x> constexpr auto constant = x;

auto v1 = constant<5>; // v1 == 5, decltype(v1) is int


auto v2 = constant<true>; // v2 == true, decltype(v2) is bool
auto v3 = constant<'a'>; // v3 == 'a', decltype(v3) is char

Templates as template parameters


A template can be a template parameter. In this example, MyClass2 has two template
parameters: a typename parameter T and a template parameter Arr:

C++

template<typename T, template<typename U, int I> class Arr>


class MyClass2
{
T t; //OK
Arr<T, 10> a;
U u; //Error. U not in scope
};

Because the Arr parameter itself has no body, its parameter names are not needed. In
fact, it is an error to refer to Arr's typename or class parameter names from within the
body of MyClass2 . For this reason, Arr's type parameter names can be omitted, as shown
in this example:

C++

template<typename T, template<typename, int> class Arr>


class MyClass2
{
T t; //OK
Arr<T, 10> a;
};

Default template arguments


Class and function templates can have default arguments. When a template has a
default argument you can leave it unspecified when you use it. For example, the
std::vector template has a default argument for the allocator:

C++

template <class T, class Allocator = allocator<T>> class vector;


In most cases the default std::allocator class is acceptable, so you use a vector like this:

C++

vector<int> myInts;

But if necessary you can specify a custom allocator like this:

C++

vector<int, MyAllocator> ints;

For multiple template arguments, all arguments after the first default argument must
have default arguments.

When using a template whose parameters are all defaulted, use empty angle brackets:

C++

template<typename A = int, typename B = double>


class Bar
{
//...
};
...
int main()
{
Bar<> bar; // use all default type arguments
}

Template specialization
In some cases, it isn't possible or desirable for a template to define exactly the same
code for any type. For example, you might wish to define a code path to be executed
only if the type argument is a pointer, or a std::wstring, or a type derived from a
particular base class. In such cases you can define a specialization of the template for
that particular type. When a user instantiates the template with that type, the compiler
uses the specialization to generate the class, and for all other types, the compiler
chooses the more general template. Specializations in which all parameters are
specialized are complete specializations. If only some of the parameters are specialized, it
is called a partial specialization.

C++
template <typename K, typename V>
class MyMap{/*...*/};

// partial specialization for string keys


template<typename V>
class MyMap<string, V> {/*...*/};
...
MyMap<int, MyClass> classes; // uses original template
MyMap<string, MyClass> classes2; // uses the partial specialization

A template can have any number of specializations as long as each specialized type
parameter is unique. Only class templates may be partially specialized. All complete and
partial specializations of a template must be declared in the same namespace as the
original template.

For more information, see Template Specialization.


typename
Article • 09/28/2022

In template definitions, typename provides a hint to the compiler that an unknown


identifier is a type. In template parameter lists, it's used to specify a type parameter.

Syntax
typename identifier ;

Remarks
The typename keyword must be used if a name in a template definition is a qualified
name that is dependent on a template argument; it's optional if the qualified name isn't
dependent. For more information, see Templates and Name Resolution.

typename can be used by any type anywhere in a template declaration or definition. It


isn't allowed in the base class list, unless as a template argument to a template base
class.

C++

template <class T>


class C1 : typename T::InnerType // Error - typename not allowed.
{};
template <class T>
class C2 : A<typename T::InnerType> // typename OK.
{};

The typename keyword can also be used in place of class in template parameter lists.
For example, the following statements are semantically equivalent:

C++

template<class T1, class T2>...


template<typename T1, typename T2>...

Example
C++
// typename.cpp
template<class T> class X
{
typename T::Y m_y; // treat Y as a type
};

int main()
{
}

See also
Templates
Keywords
Class Templates
Article • 07/01/2022

This article describes rules that are specific to C++ class templates.

Member functions of class templates


Member functions can be defined inside or outside of a class template. They're defined
like function templates if defined outside the class template.

C++

// member_function_templates1.cpp
template<class T, int i> class MyStack
{
T* pStack;
T StackBuffer[i];
static const int cItems = i * sizeof(T);
public:
MyStack( void );
void push( const T item );
T& pop( void );
};

template< class T, int i > MyStack< T, i >::MyStack( void )


{
};

template< class T, int i > void MyStack< T, i >::push( const T item )


{
};

template< class T, int i > T& MyStack< T, i >::pop( void )


{
};

int main()
{
}

As with any template class member function, the definition of the class's constructor
member function includes the template argument list twice.

Member functions can themselves be function templates and specify extra parameters,
as in the following example.

C++
// member_templates.cpp
template<typename T>
class X
{
public:
template<typename U>
void mf(const U &u);
};

template<typename T> template <typename U>


void X<T>::mf(const U &u)
{
}

int main()
{
}

Nested class templates


Templates can be defined within classes or class templates, in which case they're
referred to as member templates. Member templates that are classes are referred to as
nested class templates. Member templates that are functions are discussed in Member
Function Templates.

Nested class templates are declared as class templates inside the scope of the outer
class. They can be defined inside or outside of the enclosing class.

The following code demonstrates a nested class template inside an ordinary class.

C++

// nested_class_template1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

class X
{

template <class T>


struct Y
{
T m_t;
Y(T t): m_t(t) { }
};

Y<int> yInt;
Y<char> yChar;
public:
X(int i, char c) : yInt(i), yChar(c) { }
void print()
{
cout << yInt.m_t << " " << yChar.m_t << endl;
}
};

int main()
{
X x(1, 'a');
x.print();
}

The following code uses nested template type parameters to create nested class
templates:

C++

// nested_class_template2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

template <class T>


class X
{
template <class U> class Y
{
U* u;
public:
Y();
U& Value();
void print();
~Y();
};

Y<int> y;
public:
X(T t) { y.Value() = t; }
void print() { y.print(); }
};

template <class T>


template <class U>
X<T>::Y<U>::Y()
{
cout << "X<T>::Y<U>::Y()" << endl;
u = new U();
}

template <class T>


template <class U>
U& X<T>::Y<U>::Value()
{
return *u;
}

template <class T>


template <class U>
void X<T>::Y<U>::print()
{
cout << this->Value() << endl;
}

template <class T>


template <class U>
X<T>::Y<U>::~Y()
{
cout << "X<T>::Y<U>::~Y()" << endl;
delete u;
}

int main()
{
X<int>* xi = new X<int>(10);
X<char>* xc = new X<char>('c');
xi->print();
xc->print();
delete xi;
delete xc;
}

/* Output:
X<T>::Y<U>::Y()
X<T>::Y<U>::Y()
10
99
X<T>::Y<U>::~Y()
X<T>::Y<U>::~Y()
*/

Local classes aren't allowed to have member templates.

Template friends
Class templates can have friends. A class or class template, function, or function
template can be a friend to a template class. Friends can also be specializations of a
class template or function template, but not partial specializations.

In the following example, a friend function is defined as a function template within the
class template. This code produces a version of the friend function for every
instantiation of the template. This construct is useful if your friend function depends on
the same template parameters as the class does.

C++

// template_friend1.cpp
// compile with: /EHsc

#include <iostream>
using namespace std;

template <class T> class Array {


T* array;
int size;

public:
Array(int sz): size(sz) {
array = new T[size];
memset(array, 0, size * sizeof(T));
}

Array(const Array& a) {
size = a.size;
array = new T[size];
memcpy_s(array, a.array, sizeof(T));
}

T& operator[](int i) {
return *(array + i);
}

int Length() { return size; }

void print() {
for (int i = 0; i < size; i++)
cout << *(array + i) << " ";

cout << endl;


}

template<class T>
friend Array<T>* combine(Array<T>& a1, Array<T>& a2);
};

template<class T>
Array<T>* combine(Array<T>& a1, Array<T>& a2) {
Array<T>* a = new Array<T>(a1.size + a2.size);
for (int i = 0; i < a1.size; i++)
(*a)[i] = *(a1.array + i);

for (int i = 0; i < a2.size; i++)


(*a)[i + a1.size] = *(a2.array + i);

return a;
}

int main() {
Array<char> alpha1(26);
for (int i = 0 ; i < alpha1.Length() ; i++)
alpha1[i] = 'A' + i;

alpha1.print();

Array<char> alpha2(26);
for (int i = 0 ; i < alpha2.Length() ; i++)
alpha2[i] = 'a' + i;

alpha2.print();
Array<char>*alpha3 = combine(alpha1, alpha2);
alpha3->print();
delete alpha3;
}
/* Output:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l
m n o p q r s t u v w x y z
*/

The next example involves a friend that has a template specialization. A function
template specialization is automatically a friend if the original function template is a
friend.

It's also possible to declare only the specialized version of the template as the friend, as
the comment before the friend declaration in the following code indicates. If you declare
a specialization as a friend, you must put the definition of the friend template
specialization outside of the template class.

C++

// template_friend2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

template <class T>


class Array;

template <class T>


void f(Array<T>& a);

template <class T> class Array


{
T* array;
int size;
public:
Array(int sz): size(sz)
{
array = new T[size];
memset(array, 0, size * sizeof(T));
}
Array(const Array& a)
{
size = a.size;
array = new T[size];
memcpy_s(array, a.array, sizeof(T));
}
T& operator[](int i)
{
return *(array + i);
}
int Length()
{
return size;
}
void print()
{
for (int i = 0; i < size; i++)
{
cout << *(array + i) << " ";
}
cout << endl;
}
// If you replace the friend declaration with the int-specific
// version, only the int specialization will be a friend.
// The code in the generic f will fail
// with C2248: 'Array<T>::size' :
// cannot access private member declared in class 'Array<T>'.
//friend void f<int>(Array<int>& a);

friend void f<>(Array<T>& a);


};

// f function template, friend of Array<T>


template <class T>
void f(Array<T>& a)
{
cout << a.size << " generic" << endl;
}

// Specialization of f for int arrays


// will be a friend because the template f is a friend.
template<> void f(Array<int>& a)
{
cout << a.size << " int" << endl;
}

int main()
{
Array<char> ac(10);
f(ac);

Array<int> a(10);
f(a);
}
/* Output:
10 generic
10 int
*/

The next example shows a friend class template declared within a class template. The
class template is then used as the template argument for the friend class. Friend class
templates must be defined outside of the class template in which they're declared. Any
specializations or partial specializations of the friend template are also friends of the
original class template.

C++

// template_friend3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

template <class T>


class X
{
private:
T* data;
void InitData(int seed) { data = new T(seed); }
public:
void print() { cout << *data << endl; }
template <class U> friend class Factory;
};

template <class U>


class Factory
{
public:
U* GetNewObject(int seed)
{
U* pu = new U;
pu->InitData(seed);
return pu;
}
};

int main()
{
Factory< X<int> > XintFactory;
X<int>* x1 = XintFactory.GetNewObject(65);
X<int>* x2 = XintFactory.GetNewObject(97);
Factory< X<char> > XcharFactory;
X<char>* x3 = XcharFactory.GetNewObject(65);
X<char>* x4 = XcharFactory.GetNewObject(97);
x1->print();
x2->print();
x3->print();
x4->print();
}
/* Output:
65
97
A
a
*/

Reuse of Template Parameters


Template parameters can be reused in the template parameter list. For example, the
following code is allowed:

C++

// template_specifications2.cpp

class Y
{
};
template<class T, T* pT> class X1
{
};
template<class T1, class T2 = T1> class X2
{
};

Y aY;

X1<Y, &aY> x1;


X2<int> x2;

int main()
{
}

See also
Templates
Function Templates
Article • 08/03/2021

Class templates define a family of related classes that are based on the type arguments
passed to the class upon instantiation. Function templates are similar to class templates
but define a family of functions. With function templates, you can specify a set of
functions that are based on the same code but act on different types or classes. The
following function template swaps two items:

C++

// function_templates1.cpp
template< class T > void MySwap( T& a, T& b ) {
T c(a);
a = b;
b = c;
}
int main() {
}

This code defines a family of functions that swap the values of the arguments. From this
template, you can generate functions that will swap int and long types and also user-
defined types. MySwap will even swap classes if the class's copy constructor and
assignment operator are properly defined.

In addition, the function template will prevent you from swapping objects of different
types, because the compiler knows the types of the a and b parameters at compile time.

Although this function could be performed by a nontemplated function, using void


pointers, the template version is typesafe. Consider the following calls:

C++

int j = 10;
int k = 18;
CString Hello = "Hello, Windows!";
MySwap( j, k ); //OK
MySwap( j, Hello ); //error

The second MySwap call triggers a compile-time error, because the compiler cannot
generate a MySwap function with parameters of different types. If void pointers were
used, both function calls would compile correctly, but the function would not work
properly at run time.
Explicit specification of the template arguments for a function template is allowed. For
example:

C++

// function_templates2.cpp
template<class T> void f(T) {}
int main(int j) {
f<char>(j); // Generate the specialization f(char).
// If not explicitly specified, f(int) would be deduced.
}

When the template argument is explicitly specified, normal implicit conversions are
done to convert the function argument to the type of the corresponding function
template parameters. In the above example, the compiler will convert j to type char .

See also
Templates
Function Template Instantiation
Explicit Instantiation
Explicit Specialization of Function Templates
Function Template Instantiation
Article • 08/03/2021

When a function template is first called for each type, the compiler creates an
instantiation. Each instantiation is a version of the templated function specialized for the
type. This instantiation will be called every time the function is used for the type. If you
have several identical instantiations, even in different modules, only one copy of the
instantiation will end up in the executable file.

Conversion of function arguments is allowed in function templates for any argument


and parameter pair where the parameter does not depend on a template argument.

Function templates can be explicitly instantiated by declaring the template with a


particular type as an argument. For example, the following code is allowed:

C++

// function_template_instantiation.cpp
template<class T> void f(T) { }

// Instantiate f with the explicitly specified template.


// argument 'int'
//
template void f<int> (int);

// Instantiate f with the deduced template argument 'char'.


template void f(char);
int main()
{
}

See also
Function Templates
Explicit instantiation
Article • 09/28/2022

You can use explicit instantiation to create an instantiation of a templated class or


function without actually using it in your code. Because it's useful when you're creating
library ( .lib ) files that use templates for distribution, uninstantiated template
definitions aren't put into object ( .obj ) files.

Examples
This code explicitly instantiates MyStack for int variables and six items:

C++

template class MyStack<int, 6>;

This statement creates an instantiation of MyStack without reserving any storage for an
object. Code is generated for all members.

The next line explicitly instantiates only the constructor member function:

C++

template MyStack<int, 6>::MyStack( void );

You can explicitly instantiate function templates by using a specific type argument to
redeclare them, as shown in the example in Function template instantiation.

You can use the extern keyword to prevent the automatic instantiation of members. For
example:

C++

extern template class MyStack<int, 6>;

Similarly, you can mark specific members as being external and not instantiated:

C++

extern template MyStack<int, 6>::MyStack( void );


You can use the extern keyword to keep the compiler from generating the same
instantiation code in more than one object module. You must instantiate the function
template by using the specified explicit template parameters in at least one linked
module if the function is called. Otherwise, you'll get a linker error when the program is
built.

7 Note

The extern keyword in the specialization only applies to member functions defined
outside of the body of the class. Functions defined inside the class declaration are
considered inline functions and are always instantiated.

See also
Function templates
Explicit Specialization of Function
Templates
Article • 08/03/2021

With a function template, you can define special behavior for a specific type by
providing an explicit specialization (override) of the function template for that type. For
example:

C++

template<> void MySwap(double a, double b);

This declaration enables you to define a different function for double variables. Like
non-template functions, standard type conversions (such as promoting a variable of
type float to double ) are applied.

Example
C++

// explicit_specialization.cpp
template<class T> void f(T t)
{
};

// Explicit specialization of f with 'char' with the


// template argument explicitly specified:
//
template<> void f<char>(char c)
{
}

// Explicit specialization of f with 'double' with the


// template argument deduced:
//
template<> void f(double d)
{
}
int main()
{
}

See also
Function Templates
Partial ordering of function templates
(C++)
Article • 09/28/2022

Multiple function templates that match the argument list of a function call can be
available. C++ defines a partial ordering of function templates to specify which function
should be called. The ordering is partial because there can be some templates that are
considered equally specialized.

The compiler chooses the most specialized function template available from the
possible matches. For example, if a function template takes a type T and another
function template that takes T* is available, the T* version is said to be more
specialized. It's preferred over the generic T version whenever the argument is a pointer
type, even though both would be allowable matches.

Use the following process to determine if one function template candidate is more
specialized:

1. Consider two function templates, T1 and T2 .

2. Replace the parameters in T1 with a hypothetical unique type X .

3. With the parameter list in T1 , see if T2 is a valid template for that parameter list.
Ignore any implicit conversions.

4. Repeat the same process with T1 and T2 reversed.

5. If one template is a valid template argument list for the other template, but the
converse isn't true, then that template is considered to be less specialized than the
other template. If by using the previous step, both templates form valid arguments
for each other, then they're considered to be equally specialized, and an
ambiguous call results when you attempt to use them.

6. Using these rules:

a. A template specialization for a specific type is more specialized than one taking
a generic type argument.

b. A template taking only T* is more specialized than one taking only T , because
a hypothetical type X* is a valid argument for a T template argument, but X
isn't a valid argument for a T* template argument.
c. const T is more specialized than T , because const X is a valid argument for a
T template argument, but X isn't a valid argument for a const T template
argument.

d. const T* is more specialized than T* , because const X* is a valid argument for


a T* template argument, but X* isn't a valid argument for a const T* template
argument.

Example
The following sample works as specified in the standard:

C++

// partial_ordering_of_function_templates.cpp
// compile with: /EHsc
#include <iostream>

template <class T> void f(T) {


printf_s("Less specialized function called\n");
}

template <class T> void f(T*) {


printf_s("More specialized function called\n");
}

template <class T> void f(const T*) {


printf_s("Even more specialized function for const T*\n");
}

int main() {
int i =0;
const int j = 0;
int *pi = &i;
const int *cpi = &j;

f(i); // Calls less specialized function.


f(pi); // Calls more specialized function.
f(cpi); // Calls even more specialized function.
// Without partial ordering, these calls would be ambiguous.
}

Output
Output
Less specialized function called
More specialized function called
Even more specialized function for const T*

See also
Function templates
Member function templates
Article • 09/28/2022

The term member template refers to both member function templates and nested class
templates. Member function templates are function templates that are members of a
class or class template.

Member functions can be function templates in several contexts. All functions of class
templates are generic but aren't referred to as member templates or member function
templates. If these member functions take their own template arguments, they're
considered to be member function templates.

Example: Declare member function templates


Member function templates of non-template classes or class templates are declared as
function templates with their template parameters.

C++

// member_function_templates.cpp
struct X
{
template <class T> void mf(T* t) {}
};

int main()
{
int i;
X* x = new X();
x->mf(&i);
}

Example: Member function template of a class


template
The following example shows a member function template of a class template.

C++

// member_function_templates2.cpp
template<typename T>
class X
{
public:
template<typename U>
void mf(const U &u)
{
}
};

int main()
{
}

Example: Define member templates outside


class
C++

// defining_member_templates_outside_class.cpp
template<typename T>
class X
{
public:
template<typename U>
void mf(const U &u);
};

template<typename T> template <typename U>


void X<T>::mf(const U &u)
{
}

int main()
{
}

Example: Templated user-defined conversion


Local classes aren't allowed to have member templates.

Member function templates can't be virtual functions. And, they can't override virtual
functions from a base class when they're declared with the same name as a base class
virtual function.

The following example shows a templated user-defined conversion:

C++
// templated_user_defined_conversions.cpp
template <class T>
struct S
{
template <class U> operator S<U>()
{
return S<U>();
}
};

int main()
{
S<int> s1;
S<long> s2 = s1; // Convert s1 using UDC and copy constructs S<long>.
}

See also
Function templates
Template Specialization (C++)
Article • 08/03/2021

Class templates can be partially specialized, and the resulting class is still a template.
Partial specialization allows template code to be partially customized for specific types in
situations, such as:

A template has multiple types and only some of them need to be specialized. The
result is a template parameterized on the remaining types.

A template has only one type, but a specialization is needed for pointer, reference,
pointer to member, or function pointer types. The specialization itself is still a
template on the type pointed to or referenced.

Example: Partial specialization of class


templates
C++

// partial_specialization_of_class_templates.cpp
#include <stdio.h>

template <class T> struct PTS {


enum {
IsPointer = 0,
IsPointerToDataMember = 0
};
};

template <class T> struct PTS<T*> {


enum {
IsPointer = 1,
IsPointerToDataMember = 0
};
};

template <class T, class U> struct PTS<T U::*> {


enum {
IsPointer = 0,
IsPointerToDataMember = 1
};
};

struct S{};

int main() {
printf_s("PTS<S>::IsPointer == %d \nPTS<S>::IsPointerToDataMember ==
%d\n",
PTS<S>::IsPointer, PTS<S>:: IsPointerToDataMember);
printf_s("PTS<S*>::IsPointer == %d \nPTS<S*>::IsPointerToDataMember ==
%d\n"
, PTS<S*>::IsPointer, PTS<S*>:: IsPointerToDataMember);
printf_s("PTS<int S::*>::IsPointer == %d \nPTS"
"<int S::*>::IsPointerToDataMember == %d\n",
PTS<int S::*>::IsPointer, PTS<int S::*>::
IsPointerToDataMember);
}

Output

PTS<S>::IsPointer == 0
PTS<S>::IsPointerToDataMember == 0
PTS<S*>::IsPointer == 1
PTS<S*>::IsPointerToDataMember == 0
PTS<int S::*>::IsPointer == 0
PTS<int S::*>::IsPointerToDataMember == 1

Example: Partial specialization for pointer types


If you have a template collection class that takes any type T , you can create a partial
specialization that takes any pointer type T* . The following code demonstrates a
collection class template Bag and a partial specialization for pointer types in which the
collection dereferences the pointer types before copying them to the array. The
collection then stores the values that are pointed to. With the original template, only the
pointers themselves would have been stored in the collection, leaving the data
vulnerable to deletion or modification. In this special pointer version of the collection,
code to check for a null pointer in the add method is added.

C++

// partial_specialization_of_class_templates2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

// Original template collection class.


template <class T> class Bag {
T* elem;
int size;
int max_size;

public:
Bag() : elem(0), size(0), max_size(1) {}
void add(T t) {
T* tmp;
if (size + 1 >= max_size) {
max_size *= 2;
tmp = new T [max_size];
for (int i = 0; i < size; i++)
tmp[i] = elem[i];
tmp[size++] = t;
delete[] elem;
elem = tmp;
}
else
elem[size++] = t;
}

void print() {
for (int i = 0; i < size; i++)
cout << elem[i] << " ";
cout << endl;
}
};

// Template partial specialization for pointer types.


// The collection has been modified to check for NULL
// and store types pointed to.
template <class T> class Bag<T*> {
T* elem;
int size;
int max_size;

public:
Bag() : elem(0), size(0), max_size(1) {}
void add(T* t) {
T* tmp;
if (t == NULL) { // Check for NULL
cout << "Null pointer!" << endl;
return;
}

if (size + 1 >= max_size) {


max_size *= 2;
tmp = new T [max_size];
for (int i = 0; i < size; i++)
tmp[i] = elem[i];
tmp[size++] = *t; // Dereference
delete[] elem;
elem = tmp;
}
else
elem[size++] = *t; // Dereference
}

void print() {
for (int i = 0; i < size; i++)
cout << elem[i] << " ";
cout << endl;
}
};

int main() {
Bag<int> xi;
Bag<char> xc;
Bag<int*> xp; // Uses partial specialization for pointer types.

xi.add(10);
xi.add(9);
xi.add(8);
xi.print();

xc.add('a');
xc.add('b');
xc.add('c');
xc.print();

int i = 3, j = 87, *p = new int[2];


*p = 8;
*(p + 1) = 100;
xp.add(&i);
xp.add(&j);
xp.add(p);
xp.add(p + 1);
delete[] p;
p = NULL;
xp.add(p);
xp.print();
}

Output

10 9 8
a b c
Null pointer!
3 87 8 100

Example: Define partial specialization so one


type is int
The following example defines a template class that takes pairs of any two types and
then defines a partial specialization of that template class specialized so that one of the
types is int . The specialization defines an additional sort method that implements a
simple bubble sort based on the integer.

C++
// partial_specialization_of_class_templates3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

template <class Key, class Value> class Dictionary {


Key* keys;
Value* values;
int size;
int max_size;
public:
Dictionary(int initial_size) : size(0) {
max_size = 1;
while (initial_size >= max_size)
max_size *= 2;
keys = new Key[max_size];
values = new Value[max_size];
}
void add(Key key, Value value) {
Key* tmpKey;
Value* tmpVal;
if (size + 1 >= max_size) {
max_size *= 2;
tmpKey = new Key [max_size];
tmpVal = new Value [max_size];
for (int i = 0; i < size; i++) {
tmpKey[i] = keys[i];
tmpVal[i] = values[i];
}
tmpKey[size] = key;
tmpVal[size] = value;
delete[] keys;
delete[] values;
keys = tmpKey;
values = tmpVal;
}
else {
keys[size] = key;
values[size] = value;
}
size++;
}

void print() {
for (int i = 0; i < size; i++)
cout << "{" << keys[i] << ", " << values[i] << "}" << endl;
}
};

// Template partial specialization: Key is specified to be int.


template <class Value> class Dictionary<int, Value> {
int* keys;
Value* values;
int size;
int max_size;
public:
Dictionary(int initial_size) : size(0) {
max_size = 1;
while (initial_size >= max_size)
max_size *= 2;
keys = new int[max_size];
values = new Value[max_size];
}
void add(int key, Value value) {
int* tmpKey;
Value* tmpVal;
if (size + 1 >= max_size) {
max_size *= 2;
tmpKey = new int [max_size];
tmpVal = new Value [max_size];
for (int i = 0; i < size; i++) {
tmpKey[i] = keys[i];
tmpVal[i] = values[i];
}
tmpKey[size] = key;
tmpVal[size] = value;
delete[] keys;
delete[] values;
keys = tmpKey;
values = tmpVal;
}
else {
keys[size] = key;
values[size] = value;
}
size++;
}

void sort() {
// Sort method is defined.
int smallest = 0;
for (int i = 0; i < size - 1; i++) {
for (int j = i; j < size; j++) {
if (keys[j] < keys[smallest])
smallest = j;
}
swap(keys[i], keys[smallest]);
swap(values[i], values[smallest]);
}
}

void print() {
for (int i = 0; i < size; i++)
cout << "{" << keys[i] << ", " << values[i] << "}" << endl;
}
};

int main() {
Dictionary<const char*, const char*> dict(10);
dict.print();
dict.add("apple", "fruit");
dict.add("banana", "fruit");
dict.add("dog", "animal");
dict.print();

Dictionary<int, const char*> dict_specialized(10);


dict_specialized.print();
dict_specialized.add(100, "apple");
dict_specialized.add(101, "banana");
dict_specialized.add(103, "dog");
dict_specialized.add(89, "cat");
dict_specialized.print();
dict_specialized.sort();
cout << endl << "Sorted list:" << endl;
dict_specialized.print();
}

Output

{apple, fruit}
{banana, fruit}
{dog, animal}
{100, apple}
{101, banana}
{103, dog}
{89, cat}

Sorted list:
{89, cat}
{100, apple}
{101, banana}
{103, dog}
Templates and Name Resolution
Article • 08/03/2021

In template definitions, there are three types of names.

Locally declared names, including the name of the template itself and any names
declared inside the template definition.

Names from the enclosing scope outside the template definition.

Names that depend in some way on the template arguments, referred to as


dependent names.

While the first two names also pertain to class and function scopes, special rules for
name resolution are required in template definitions to deal with the added complexity
of dependent names. This is because the compiler knows little about these names until
the template is instantiated, because they could be totally different types depending on
which template arguments are used. Nondependent names are looked up according to
the usual rules and at the point of definition of the template. These names, being
independent of the template arguments, are looked up once for all template
specializations. Dependent names are not looked up until the template is instantiated
and are looked up separately for each specialization.

A type is dependent if it depends on the template arguments. Specifically, a type is


dependent if it is:

The template argument itself:

C++

A qualified name with a qualification including a dependent type:

C++

T::myType

A qualified name if the unqualified part identifies a dependent type:

C++

N::T
A const or volatile type for which the base type is a dependent type:

C++

const T

A pointer, reference, array, or function pointer type based on a dependent type:

C++

T *, T &, T [10], T (*)()

An array whose size is based on a template parameter:

C++

template <int arg> class X {


int x[arg] ; // dependent type
}

a template type constructed from a template parameter:

C++

T<int>, MyTemplate<T>

Type Dependence and Value Dependence


Names and expressions dependent on a template parameter are categorized as type
dependent or value dependent, depending on whether the template parameter is a type
parameter or a value parameter. Also, any identifiers declared in a template with a type
dependent on the template argument are considered value dependent, as is a integral
or enumeration type initialized with a value-dependent expression.

Type-dependent and value-dependent expressions are expressions that involve variables


that are type dependent or value dependent. These expressions can have semantics that
differ, depending on the parameters used for the template.

See also
Templates
Name Resolution for Dependent Types
Article • 08/03/2021

Use typename for qualified names in template definitions to tell the compiler that the
given qualified name identifies a type. For more information, see typename.

C++

// template_name_resolution1.cpp
#include <stdio.h>
template <class T> class X
{
public:
void f(typename T::myType* mt) {}
};

class Yarg
{
public:
struct myType { };
};

int main()
{
X<Yarg> x;
x.f(new Yarg::myType());
printf("Name resolved by using typename keyword.");
}

Output

Name resolved by using typename keyword.

Name lookup for dependent names examines names from both the context of the
template definition—in the following example, this context would find myFunction(char)
—and the context of the template instantiation.In the following example, the template is
instantiated in main; therefore, the MyNamespace::myFunction is visible from the point of
instantiation and is picked as the better match. If MyNamespace::myFunction were
renamed, myFunction(char) would be called instead.

All names are resolved as if they were dependent names. Nevertheless, we recommend
that you use fully qualified names if there is any possible conflict.

C++
// template_name_resolution2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

void myFunction(char)
{
cout << "Char myFunction" << endl;
}

template <class T> class Class1


{
public:
Class1(T i)
{
// If replaced with myFunction(1), myFunction(char)
// will be called
myFunction(i);
}
};

namespace MyNamespace
{
void myFunction(int)
{
cout << "Int MyNamespace::myFunction" << endl;
}
};

using namespace MyNamespace;

int main()
{
Class1<int>* c1 = new Class1<int>(100);
}

Output
Output

Int MyNamespace::myFunction

Template Disambiguation
Visual Studio 2012 enforces the C++98/03/11 standard rules for disambiguation with
the "template" keyword. In the following example, Visual Studio 2010 would accept both
the nonconforming lines and the conforming lines. Visual Studio 2012 accepts only the
conforming lines.
C++

#include <iostream>
#include <ostream>
#include <typeinfo>
using namespace std;

template <typename T> struct Allocator {


template <typename U> struct Rebind {
typedef Allocator<U> Other;
};
};

template <typename X, typename AY> struct Container {


#if defined(NONCONFORMANT)
typedef typename AY::Rebind<X>::Other AX; // nonconformant
#elif defined(CONFORMANT)
typedef typename AY::template Rebind<X>::Other AX; // conformant
#else
#error Define NONCONFORMANT or CONFORMANT.
#endif
};

int main() {
cout << typeid(Container<int, Allocator<float>>::AX).name() << endl;
}

Conformance with the disambiguation rules is required because, by default, C++


assumes that AY::Rebind isn't a template, and so the compiler interprets the following "
< " as a less-than. It has to know that Rebind is a template so that it can correctly parse
" < " as an angle bracket.

See also
Name Resolution
Name Resolution for Locally Declared
Names
Article • 09/28/2022

The template's name itself can be referred to with or without the template arguments. In
the scope of a class template, the name itself refers to the template. In the scope of a
template specialization or partial specialization, the name alone refers to the
specialization or partial specialization. Other specializations or partial specializations of
the template can also be referenced, with the appropriate template arguments.

Example: Specialization versus partial


specialization
The following code shows that the class template's name A is interpreted differently in
the scope of a specialization or partial specialization.

C++

// template_name_resolution3.cpp
// compile with: /c
template <class T> class A {
A* a1; // A refers to A<T>
A<int>* a2; // A<int> refers to a specialization of A.
A<T*>* a3; // A<T*> refers to the partial specialization A<T*>.
};

template <class T> class A<T*> {


A* a4; // A refers to A<T*>.
};

template<> class A<int> {


A* a5; // A refers to A<int>.
};

Example: Name conflict between template


parameter and object
When there's a name conflict between a template parameter and another object, the
template parameter can or can't be hidden. The following rules will help determine
precedence.
The template parameter is in scope from the point where it first appears until the end of
the class or function template. If the name appears again in the template argument list
or in the list of base classes, it refers to the same type. In standard C++, no other name
that is identical to the template parameter can be declared in the same scope. A
Microsoft extension allows the template parameter to be redefined in the scope of the
template. The following example shows using the template parameter in the base
specification of a class template.

C++

// template_name_resolution4.cpp
// compile with: /EHsc
template <class T>
class Base1 {};

template <class T>


class Derived1 : Base1<T> {};

int main() {
// Derived1<int> d;
}

Example: Define member function outside class


template
When member functions are defined outside the class template, a different template
parameter name can be used. If the class template member function's definition uses a
different name for the template parameter than the declaration does, and the name
used in the definition conflicts with another member of the declaration, the member in
the template declaration takes precedence.

C++

// template_name_resolution5.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

template <class T> class C {


public:
struct Z {
Z() { cout << "Z::Z()" << endl; }
};
void f();
};
template <class Z>
void C<Z>::f() {
// Z refers to the struct Z, not to the template arg;
// Therefore, the constructor for struct Z will be called.
Z z;
}

int main() {
C<int> c;
c.f();
}

Output

Z::Z()

Example: Define template or member function


outside namespace
When defining a function template or a member function outside the namespace in
which the template was declared, the template argument takes precedence over the
names of other members of the namespace.

C++

// template_name_resolution6.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

namespace NS {
void g() { cout << "NS::g" << endl; }

template <class T> struct C {


void f();
void g() { cout << "C<T>::g" << endl; }
};
};

template <class T>


void NS::C<T>::f() {
g(); // C<T>::g, not NS::g
};

int main() {
NS::C<int> c;
c.f();
}
Output

C<T>::g

Example: Base class or member name hides


template argument
In definitions that are outside of the template class declaration, if a template class has a
base class that doesn't depend on a template argument and if the base class or one of
its members has the same name as a template argument, then the base class or member
name hides the template argument.

C++

// template_name_resolution7.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

struct B {
int i;
void print() { cout << "Base" << endl; }
};

template <class T, int i> struct C : public B {


void f();
};

template <class B, int i>


void C<B, i>::f() {
B b; // Base class b, not template argument.
b.print();
i = 1; // Set base class's i to 1.
}

int main() {
C<int, 1> c;
c.f();
cout << c.i << endl;
}

Output

Base
1
See also
Name resolution
Overload resolution of function
template calls
Article • 09/28/2022

A function template can overload non-template functions of the same name. In this
scenario, the compiler first attempts to resolve a function call by using template
argument deduction to instantiate the function template with a unique specialization. If
template argument deduction fails, then the compiler considers both instantiated
function template overloads and non-template function overloads to resolve the call.
These other overloads are known as the candidate set. If template argument deduction
succeeds, then the generated function is compared with the other functions in the
candidate set to determine the best match, following the rules for overload resolution.
For more information, see Function overloading.

Example: Choose a non-template function


If a non-template function is an equally good match to a function template, the non-
template function is chosen (unless the template arguments were explicitly specified), as
in the call f(1, 1) in the following example.

C++

// template_name_resolution9.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

void f(int, int) { cout << "f(int, int)" << endl; }


void f(char, char) { cout << "f(char, char)" << endl; }

template <class T1, class T2>


void f(T1, T2)
{
cout << "void f(T1, T2)" << endl;
};

int main()
{
f(1, 1); // Equally good match; choose the non-template function.
f('a', 1); // Chooses the function template.
f<int, int>(2, 2); // Template arguments explicitly specified.
}

Output
f(int, int)
void f(T1, T2)
void f(T1, T2)

Example: Exact match function template


preferred
The next example illustrates that the exactly matching function template is preferred if
the non-template function requires a conversion.

C++

// template_name_resolution10.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

void f(int, int) { cout << "f(int, int)" << endl; }

template <class T1, class T2>


void f(T1, T2)
{
cout << "void f(T1, T2)" << endl;
};

int main()
{
long l = 0;
int i = 0;
// Call the function template f(long, int) because f(int, int)
// would require a conversion from long to int.
f(l, i);
}

Output

void f(T1, T2)

See also
Name resolution
typename
Source code organization (C++
Templates)
Article • 07/01/2022

When defining a class template, you must organize the source code in such a way that
the member definitions are visible to the compiler when it needs them. You have the
choice of using the inclusion model or the explicit instantiation model. In the inclusion
model, you include the member definitions in every file that uses a template. This
approach is simplest and provides maximum flexibility in terms of what concrete types
can be used with your template. Its disadvantage is that it can increase compilation
times. The times can be significant if a project or the included files themselves are large.
With the explicit instantiation approach, the template itself instantiates concrete classes
or class members for specific types. This approach can speed up compilation times, but
it limits usage to only those classes that the template implementer has enabled ahead of
time. In general, we recommend that you use the inclusion model unless the
compilation times become a problem.

Background
Templates aren't like ordinary classes in the sense that the compiler doesn't generate
object code for a template or any of its members. There's nothing to generate until the
template is instantiated with concrete types. When the compiler encounters a template
instantiation such as MyClass<int> mc; and no class with that signature exists yet, it
generates a new class. It also attempts to generate code for any member functions that
are used. If those definitions are in a file that isn't #included, directly or indirectly, in the
.cpp file that is being compiled, the compiler can't see them. From the compiler's point
of view, it's not necessarily an error. The functions may be defined in another translation
unit where the linker will find them. If the linker doesn't find that code, it raises an
unresolved external error.

The inclusion model


The simplest and most common way to make template definitions visible throughout a
translation unit, is to put the definitions in the header file itself. Any .cpp file that uses
the template simply has to #include the header. This approach is used in the Standard
Library.

C++
#ifndef MYARRAY
#define MYARRAY
#include <iostream>

template<typename T, size_t N>


class MyArray
{
T arr[N];
public:
// Full definitions:
MyArray(){}
void Print()
{
for (const auto v : arr)
{
std::cout << v << " , ";
}
}

T& operator[](int i)
{
return arr[i];
}
};
#endif

With this approach, the compiler has access to the complete template definition and can
instantiate templates on-demand for any type. It's simple and relatively easy to
maintain. However, the inclusion model does have a cost in terms of compilation times.
This cost can be significant in large programs, especially if the template header itself
#includes other headers. Every .cpp file that #includes the header will get its own copy
of the function templates and all the definitions. The linker will generally be able to sort
things out so that you don't end up with multiple definitions for a function, but it takes
time to do this work. In smaller programs that extra compilation time is probably not
significant.

The explicit instantiation model


If the inclusion model isn't viable for your project, and you know definitively the set of
types that will be used to instantiate a template, then you can separate out the template
code into an .h and .cpp file, and in the .cpp file explicitly instantiate the templates.
This approach generates object code that the compiler will see when it encounters user
instantiations.

You create an explicit instantiation by using the keyword template followed by the
signature of the entity you want to instantiate. This entity can be a type or a member. If
you explicitly instantiate a type, all members are instantiated.

The header file MyArray.h declares template class MyArray :

C++

//MyArray.h
#ifndef MYARRAY
#define MYARRAY

template<typename T, size_t N>


class MyArray
{
T arr[N];
public:
MyArray();
void Print();
T& operator[](int i);
};
#endif

The source file MyArray.cpp explicitly instantiates template MyArray<double, 5> and
template MyArray<string, 5> :

C++

//MyArray.cpp
#include <iostream>
#include "MyArray.h"

using namespace std;

template<typename T, size_t N>


MyArray<T,N>::MyArray(){}

template<typename T, size_t N>


void MyArray<T,N>::Print()
{
for (const auto v : arr)
{
cout << v << "'";
}
cout << endl;
}

template MyArray<double, 5>;


template MyArray<string, 5>;

In the previous example, the explicit instantiations are at the bottom of the .cpp file. A
MyArray may be used only for double or String types.
7 Note

In C++11 the export keyword was deprecated in the context of template


definitions. In practical terms this has little impact because most compilers never
supported it.

You might also like