22
loading...
This website collects cookies to deliver better user experience
NOTE: Like the structured, modular and object oriented approaches, generic programming is another programming approach and C++ supports all the four programming patterns.
int max(int a, int b)
{
return (a > b) ? a : b;
}
double max(double a, double b)
{
return (a > b) ? a : b;
}
#define max(a, b) ((a) > (b) ? (a) : (b))
template <typename T>
T max(T a, T b)
{
return (a > b) ? a : b;
}
NOTE: In mid 90's the templates are started with the desire to parameterize the containers.
template<typename T>
template<class T>
template
always begins a definition and declaration of a function template and class template. The <>
brackets contain a list of template parameters.NOTE: In the expression template<typename T> void get(T a) { };
, T
is parameter and when the function is called as get(10);
10
is a template argument with type int
.
typename
(or class
) tells the compiler that what follows is the name of a type. To use the template function you call it with the required type in angle-brackets (<>
).max<int>(10, 20);
max<double>(10.11, 20.22);
template <typename RT, typename T1, typename T2>
RT max(T1 a, T2 b)
{
return (a > b) ? a : b;
}
int main()
{
double x;
// note that return type cannot be deduced, so must always be specified
x = max<double, double, int>(23.9, 45); // double max<double, int>
x = max<double>(15, 11.5); // double max<int, double>
x = max<double>(15.5, 11); // double max<double, int>
return EXIT_SUCCESS;
}
decltype
to deduce the return type from the function.template<typename T1, typename T2>
auto max(T1 a, T2 b) -> decltype((a > b) ? a : b)
{
return (a > b) ? a : b;
}
NOTE: It is important to note that to evaluate the expressions inside the decltype
, the variable a
and b
should be visible to evaluate the expression. Using decltype
in place auto
in above code leads to compiler error.
template<parameter_list>
ret_type func_name(argument_list)
{
// body of function
}
int
, float
or double
types. The function requirement will be to return the summed value with the correct return type that is based on the type of the input variables.template <typename T>
T add(T a, T b)
{
return a + b;
}
+
operator does the same thing, but it is a good start.template <class T>
class class_name
{
//.....
public:
T memVar;
T memFunction(T args);
};
T
is the template argument which is a placeholder for the data type used. Inside the class body, a member variable memVar
and a member function memFunction
are both of type T
. Once a template class is defined as above, we can create class objects as follows:class_name<int> classObejct1;
class_name<float> classObject2;
class_name<char> classObject3;
template <class T>
class MyClass
{
T a, b;
public:
MyClass(T first, T second)
{
a = first;
b = second;
}
T getMaxval();
};
template <class T>
T MyClass<T>::getMaxval()
{
return (a > b) ? a : b;
}
int main()
{
MyClass<int> Obj1(50, 150);
std::cout << "Maximum of 50 and 150 = " << Obj1.getMaxval() << std::endl;
MyClass<char> Obj2('A', 'a');
std::cout << "Maximum of 'A' and 'a' = " << Obj2.getMaxval() << std::endl;
return 0;
}
/*OUTPUT
Maximum of 50 and 150 = 150
Maximum of 'A' and 'a' = a
*/
MyClass
. Inside this, we have a constructor that will initialize the two members a
and b
of the class. There is another member function getMaxval
which is also a function template that returns a maximum of a
and b
.typename type
class type
type
has been introduced in the template parameter list, then any reference to name with in the body of the template automatically refers to the type of the corresponding template argument for each instantiation, and can be used anywhere a type can normally be used.template<typename T>
T compare(T l, T r)
{
return (l > r) ? 1 : 0;
}
template<class T>
class Container
{
public:
void put(T* p);
T* get();
// other members
};
template<int N>; // N is a constant expression determined at compile time
template<size_t N, size_t M>; // N, M is a constant expression determined at compile time
//int size is a non-type parameter
template <class T, int size>
class MyType
{
T a[size];
public:
MyType()
{
for (int i = 0; i < size; i++)
a[i] = i;
}
T &operator[](int i)
{
if (i < 0 || i > size - 1)
{
std::cout << "Index value of " << i << " is out-of-bounds.\n";
exit(1);
}
return a[i];
}
};
template<typename T, size_t n>
void printValues(T (&arr)[n])
{
for(size_t i = 0; i < n; ++i)
{
std::cout << arr[i] << ' ';
}
std::cout << std::endl;
}
MyType
has non-type template parameter which is an integer (int size
) with type parameter (class T
) in the template parameter list.template <class T, size_t N = 10>
struct my_array
{
T arr[N];
};
int main()
{
/* Default parameter is ignored, N = 5 */
my_array<int, 5> a;
/* Print the length of a.arr: 5 */
std::cout << sizeof(a.arr) / sizeof(int) << std::endl;
/* Last parameter is omitted, N = 10 */
my_array<int> b;
/* Print the length of a.arr: 10 */
std::cout << sizeof(b.arr) / sizeof(int) << std::endl;
}
/*OUTPUT
5
10
*/
template<class T=int>
struct MyClass
{
void myMember(T* vec) {
// ...
}
};
MyClass obj; // is equivalent to MyClass<int> obj
MyClass<char> obj; // is equivalent to MyClass<char> obj
// This template function doesn't give correct result for char *
template <typename T>
T* max(T* a, T* b)
{
return (*a > *b) ? a : b;
}
// Explicit specialization of max function for const char *
template<>
const char* max(const char* a, const char* b)
{
return strcmp(a, b) > 0 ? a : b;
}
/**
* The below template class doesn't give correct result for below piece of code
* FindMax<const char*> Max
* const char* str1 = "Good"
* const char* str2 -= "Bye"
* const char * res = Max.getMax(str1, str2);
*/
template<typename T>
class FindMax
{
public:
T getMax(T a, T b)
{
return (a > b)? a : b;
}
};
// Hence, explicitly specialized class defined for const char *
template<>
class FindMax<const char*>
{
public:
const char* getMax(const char* a, const char* b)
{
return (strcmp(a,b) > 0)? a : b;
}
};
template <class T1, class T2>
class MyClass
{
public:
MyClass()
{
std::cout << "MyClass<T1, T2>::MyClass() --> regular constructor\n";
}
T1 _a;
T2 _b;
};
// Partial specialization class to int as second template parameter
template <class T>
class MyClass<T, int>
{
public:
MyClass()
{
std::cout << "MyClass<T, int>::MyClass() --> partial specializations\n";
}
T _a;
int _b;
};
int main()
{
MyClass<double, double> a;
MyClass<double, int> b; // partial specialization
return 0;
}
/*OUTPUT
MyClass<T1, T2>::MyClass() --> regular constructor
MyClass<T, int>::MyClass() --> partial specializations
*/
MyClass<T, int>
looks a bit like a normal template definition and a bit like an explicit specialization. The compiler knows it is a partial specialization, as a result the second declaration of the MyClass
invokes the partial specialized class during instantiation.22