Mastering C++ Templates: A Guide to Creating Your Own Custom Template Library Similar to STL
When I was in B.Tech, I used to code in C++ while my friends used Python. In competitive programming contests, my friends would always solve problems quickly using Python's built-in functions and simple syntax. However, I didn't want to switch to Python.
Then, I had an idea. Why not implement my own custom template library to make C++ easier to use and debug? I created a custom template library that included functions like isPrime(), toLowerCase(), gcd(), getPrimeFactors(), isPowerOfTwo(), and printing arrays.
Implementing these functions gave me a much deeper understanding of C++ syntax and built-in functions. After using my custom template library, I was able to solve problems much faster than my friends with less runtime, as C++ is faster than Python
If you're a C++ developer, you might have encountered the frustration of not having a similar convenience at your disposal. But with the power of the C++ templates, we can create our own template library to solve competitive programming questions more easily. We can also implement functions similar to those in other programming languages and print the contents of vectors, maps, pairs, sets, and so on.
PermalinkWe can include some more features in Custom Template Library like:
Print functions for printing Vectors, maps, sets, pairs and array of vectors etc.
We can implement functions that are used very frequently while doing Competitive programming or solving DSA questions.
For example: isPrime(), toLowerCase(),gcd(),lcm(),getPrimeFactors() etc.
We can make functions using bit manipulation, As these can be very efficient because they work directly with the bits of a number. This can be much faster than using other methods.
The time complexity of every bitwise operation is O(1). These operations are very very fast.
For example: isPowerOfTwo(),isEven(),setBit() etc.We can implement features that are there in Java but not in C++.
We can customize STL functions according to our requirements. And write our function using the overloading concept.
You might ask, Why create a separate template library? Why not just write the code in the same file?๐ค
There are several advantages to creating a separate template library, including:
Code Reusability: A custom template library can be reused in multiple projects, which can save you time and effort.
Code Maintainability: Changes or updates to the library can be applied uniformly across multiple projects.
Enhanced Debugging and Error Handling: Custom template libraries can include debugging features and error-handling mechanisms that align with your specific needs. This can greatly simplify the debugging process, and provide meaningful error messages.
Portability: A custom template library can be more portable than using a general-purpose library because it is not tied to any specific platform or compiler.
Developing a custom template library can be a valuable learning experience. It deepens your understanding of C++ templates, generic programming, and advanced language features. It also hones your problem-solving skills and encourages you to think abstractly about software design.
PermalinkHow can we make Custom Template Library?
we can make it by using a collection of .h files(header files). We can define our template classes, functions, or data structures within the header files.
Create a header file.
One of the most important things while creating a header file is to include header guards. The lines
#ifndef PRINT_H
and#define PRINT_H
are called header guards. They are used to prevent the header file from being included multiple times in the same source file.print.h:
#ifndef PRINT_H
#define PRINT_H
#endif
#ifndef: Checks to see if the macro
PRINT_H
has been defined. If it has not been defined, then the code in the header file is included.#define: Defines the macro
PRINT_H
. This prevents the header file from being included again.#endif: Ends the header guard.
- Include a function that overloads
operator <<
and prints std::vector
template <typename T>
std::ostream &operator<<(std::ostream &output, std::vector<T> &v){
output << "[ ";
for (auto x : v)
output << x << " ";
output << "]";
return output;
}
Let's take a closer look at the code above and see how it works.
Here we are using the concept of Operator Overloading of <<
the std::ostream operator. In general, <<
is used to print normal variables but by overloading this operator we can use it for printing various things like vectors, maps, pairs etc.
Template: this is a simple yet very powerful tool in C++. The simple idea is to pass the data type as a parameter so that we donโt need to write the same code for different data types. Above code works for vector<int>, vector<char> etc.
The
operator<<
the function takes two parameters: anostream
object and avector
object. And it returns andostream
object.Inside the function, we will iterate through each element and print it. And also we can keep customized error messages inside the function to debug easily.
You might be wondering why we have to use
std::
everywhere. Let me simplify it for you.
->In C++,std
is a namespace that stands for the Standard Library. It is a collection of pre-defined classes, functions, and templates provided by the C++ language.->When we write
std::vector
, we are referring to thevector
of the class provided by the Standard Library. This helps avoid naming conflicts with other classes or libraries that might define theirvector
class.->To avoid writing
std::
multiple times we can useusing namespace std;
.When we use this, It imports all names from thestd
namespace into the current scope. This means you can directly use names such ascout
,vector
,string
, and so on, without the need for thestd::
prefix.
- Now we can use the above function by including the print.h file in your main file.
#include<iostream>
#include "print.h"
using namespace std;
int main(){
int a[3]={1,2,3};
vector<int> v = {1,2,3};
cout<<v;
return 0;
}
Output:
[ 1 2 3 ]
"print.h" vs <print.h>: The
<print.h>
syntax is typically used for header files that are part of the standard library, while the"print.h"
syntax is typically used for header files that are created by the programmer.
These are the sample functions that I have implemented in my Custom Template Library.
sample.h :
#ifndef SAMPLE_H
#define SAMPLE_H
// for finding if the number is power of 2 or not
int isPowerof2(int num){
return (num && !(num & num-1));
}
// for finding GCD
template<typename T> T
gcd(T a, T b){
return(b?__gcd(a,b):a);
}
// For printing pair
template<typename T1,typename T2>
std::ostream & operator<<(std::ostream &out,std::pair<T1,T2> &p){
out<<"["<<p.first<<","<<p.second<<"]";
return out;
}
#endif
For more functions, you can refer to my GitHub repository(C++ Custom Template Library)