Learn to Code via Tutorials on Repl.it!

← Back to all posts

## Introduction

If you are a student like me, then most likely your school has been closed due to bad weather Coronavirus. That means that you have more time to code, but no teacher to teach you how to code. Well, that’s why I made this tutorial (I’m also just really bored). I also posted a some code that acts as a reference. Oh, and this is for everyone, not just students. Enjoy!

1. What is the Standard Template Library?
2. What will this tutorial cover?
3. Introduction to STL
4. Vectors and Deques
5. Iterators
6. Lists and Forward Lists
7. Sets and Multisets
8. Maps and Multimaps
9. Conclusion

# What is the Standard Template Library?

The Standard Template Library, or STL for short, is a group of template classes (I’ll talk more about these in a moment) and functions that can be split up into three main categories:

Containers (stores data)
Iterators (access data)
Algorithms (manipulate data)

For example, I’m sure most of you have used `std::string` before. But did you know, `std::string` is actually part of the STL!? I know, crazy! But think about it. `std::string` itself is a container that stores information (a list of characters), and you can use algorithms such as `.find()` or `.erase()` to access and manipulate data in the string (note that `std::string` is however a little different from the average container, which is why we won’t be covering it here).

Other common examples include `std::vector` and `std::map`. As you can see, the STL is nothing more than a bunch of lists, iterators, and algorithms, so don’t be frightened by its name.

# What will this tutorial cover?

So now you actually know what the STL is, let’s talk about what this tutorial will be covering. This tutorial will be divided up into different sections, each focusing around a specific container. In each section, we will be looking at what that container is, the advantages and disadvantages of it, and how it can be used. There will also be some mini sections that explore some other interesting topics about things you can do with containers.

And what about prerequisites?

You already should know about C++ static arrays, and how they can be utilized in different ways. You should already be comfortable using strings, as it may be hard to follow if you don’t. Pointer basics should also be known. And in addition, knowing a few STL containers may help as well, such as `std::vector`, but it’s fine if you don’t.

And as a bonus to fully understand this course, knowledge of templates and classes can be handy. Because remember, all that a STL container is, is a template class.

So at the very least, you should know:

Basic arrays and how to use them
Strings and how to use them
Pointers and what they are

Now, let’s get learning!

## STL Containers

First off, let’s start by going over the STL containers. Along the way, we will also naturally use some algorithms and iterators to help us explain what each container does. But now that I think about it, this section is actually about everything. Umm… anyway, let’s move on!

# Another Introduction

Let’s quickly take a look at the different types of containers.

Sequential Containers

`std::vector` and `std::deque`
`std::list` and `std::forward_list`

Associative Containers

`std::set` and `std::multiset`
`std::unordered_set` and `std::unorderd_multiset`
`std::map` and `std::multimap`
`std::unordered_map` and `std::unordered_multimap`

Now you may have noticed that there are two types of containers (there’s actually a third one, but that’s for another tutorial). First off, the sequential containers. These are just as the name sounds, sequential. They hold data in a sequence, hence the name. These are your normal arrays. They are usually characterized for their fast insertion time, but they have slow searches (time complexity is also for another tutorial, but for now, just know that some containers are faster than others at specific tasks). Oh, and for a more in depth analysis of time complexity, check out this link.

Associative containers on the other hand, store data in a sorted fashion, like a dictionary. Every word in the dictionary has a definition. Every key in an associative container has a value. As for the time complexity, it’s the exact opposite of a sequential container, with slow insertion times, but fast searches.

Now, since all these are template classes, they all follow the same syntax. Let’s use a vector and take a look at the syntax.

``````// all STL containers have their unique header file
#include <vector>

std::vector<int> integerVector;
std::vector<char> characterVector;``````

As you can see, a STL container is nothing more than a class with a template. And this format is the same across all containers. For example, if we were to create a list, then it would look like this:

``````#include <list>

std::list<int> integerList;``````

But be careful! Not all algorithms work for each container. Some are just specific to certain types.

Okay, now that you have a pretty good understanding of a STL container, let’s take a look at the different types.

# Vectors and Deques

The “generic” dynamic array. If you are just looking for a quick to use dynamic array, then these two choices are perfect for you! Let’s explore each one in detail.

`std::vector`

A vector can be visualized as a list of elements, with insertion and removal at the end (constant time). You can also insert and remove elements in the middle, however the time complexity for that is linear (so it’s just much better to use a list for that).

Oh, and I’m going to be using the standard namespace in my examples as I feel like it makes the code easier to read. But in an actual coding project, don’t use it.

You can instantiate a vector like this (just like a normal static array):

``````#include <vector> // don’t forget the header!

vector<char> charVector; // a blank slate
vector<int> intVector = { 5, 15, 20, 25, 30, 35, 35, 45, 50 }; // this is called list initialization``````

So those are the two most common uses of instantiating a vector. There are of course more ways, but it would take way too long to cover them all.

Now let’s talk about insertion and removal at the end.

``````intVector.pop_back(); // removes last element
intVector.push_back(55); // add element to the back

// oops, I made a mistake! I have to change the last element to 50!
intVector[intVector.size() - 1] = 50;

// oops, I made another mistake! Now I have to restart!
intVector.clear(); // remove all elements
if (intVector.empty()) // check to see if vector is empty
cout << “vector cleared!”;``````

The first two lines show how you can remove and add an element at the back of the vector. You could also insert an element in the middle of a vector (using `.insert()`), but that’s not what vectors are for. It's better to use a list instead (I’ll talk about those in the next section).

The fifth line shows how to access and change an element of a vector, just like a normal array. In fact, everything you can do to a normal array, you can do to a vector!

The seventh line clears the vector, removing all the elements, and the if statement checks to see if the elements actually have been cleared. Note that `.clear()` and `.empty()` work for all containers.

For more info about vectors.

Now let’s look at something interesting, the size and capacity of a vector.

``````vector<char> charVector = { ‘s’, ‘q’, ‘u’, ‘i’, ‘d’ };

cout << charVector.size(); // size: 5
cout << charVector.capacity(); // capacity: 5``````

So from the example, we created a vector. Then we printed the size and capacity of the vector to the console. Now for the size of the vector, that’s easy, it’s 5. The size of a vector (or any array) is the number of elements it stores. The capacity is also 5.

But what happens if you add an element?

``charVector.push_back(‘s’);``

The size changes to 6, and that’s expected. But the capacity, it changes to 7. Well, on Visual Studio at least. On repl.it, the capacity is 6. So what is the capacity, and why is it different on different compilers?

The capacity of a vector states how much memory it has allocated. So even if the size of a vector is 6, the vector could have allocated 7 memory slots, just to save time in the future. But this isn’t regulated by any standard, so your compiler may have allocated an additional 5 slots, while mine may have only allocated an additional 2 slots. Repl.it’s compiler allocates 1 slot everytime a element is added, so the element and size are the same.

Let’s understand this better with an example:

``````vector<int> intVector = { 's', 'q', 'i', 'u', 'd' };
cout << intVector.capacity() << endl; // size: 5, capacity: 5

intVector.push_back('s');
cout << intVector.capacity() << endl; //size: 6, capacity: 7

intVector.push_back('!');
cout << intVector.capacity(); // size: 7, capacity: 7``````

As you can see, we start off with a capacity of 5. But when we add an element, the vector doesn’t have enough space, so it resizes to 7. But when we add another element, the vector already has enough space, so it doesn’t need to resize. And remember, your compiler may resize by 5 each time. VS just chose to resize it by 2 each time. There just is no standard for resizing.

If you are still confused. Think of it like this. You have a box that can hold 10 balls, but you only have 5 balls in it. The size would be 5, but the capacity would be 10.

In fact, you can actually clear a vector using `.clear()`, and the capacity wouldn’t change!

But let’s say that you don’t want the capacity of the vector to ever go past 10, because you know that your vector will only hold at max 10 elements. Or perhaps you want to make the capacity smaller. You can actually control a vector's capacity by using the reserve method.

``intVector.reserve(10); // now the capacity is fixed at 10``

This is useful for saving down on memory in certain situations. If you would like more information, check out this link.

`std::deque`

Pronounced: “deck”. Stands for “double ended queue”.

The deque is basically the same as a vector, but it allows insertion at the front and back of the array! Oh and just like a vector, you could also insert elements at the middle, but lists are much better for that task.

``````#include <deque> // don’t forget the header!

deque<char> charDeque;

intDeque.push_back(‘i’);
intDeque.push_back(‘d’);
intDeque.push_front(‘u’); // add element to front
intDeque.push_front(‘q’);
intDeque.push_front(’s’);
intDeque.pop_front(); // remove first element``````

It also works with all the vector functions we talked about, except for `.reserve()` and `.capacity()`. Deques doesn’t have those.

Find out more differences between the two.

# Iterators

So STL containers (except for vector and deque) have this weird thing where they don’t support the random access operator `[]`. That means while a normal array can do this: `intArray = 10`, a STL container can not. So how do we access elements in a container? Iterators.

An iterator is basically like a pointer. It’s a variable that points to an element. You can use it like the follow (you don’t have to use iterators with vectors, but for the purpose of the lesson, we’re going to use vectors for this example):

``````vector<int> intVector = { 1, 2, 3, 4, 5 };
vector<int>::iterator element = integers.begin(); // create a variable called ‘element’ that points to the first element of the vector

cout << “the first element in the vector is: ” << element;

++element;

cout << ”the second element in the vector is: “ << element;``````

As you can see. We created a variable called `element`, and had it point to the first element in the array. Notice how we used `vector<int>::iterator` to define ‘element’ as an iterator. We also used the function `.begin()`. At this stage, don’t let new keywords scare you. All that `.begin()` does is set the pointer to the beginning of the array.

Now let’s say that you have a list. It would still work the same:

``````list<int> intList = { 1, 2, 3, 4, 5 };
list<int>::iterator element = intList.begin();``````

But you might have noticed something - the syntax is very clumsy! Don’t worry, there’s an easier way! Use `auto`!

``````vector<int>::iterator element = intVector.begin(); // you could do this, or…
auto element = intVector.begin(); // you could do this!``````

Now if you don’t know what `auto` is, then what it does is it automatically determines the variable type for you!

Anyway, let’s move on to some uses with iterators. So for normal arrays, you would print out their elements like this:

``````for (int i = 0; i < array.size(); ++i)
cout << array[i];``````

But again, STL containers are weird, so you can’t do that. Instead, you have to do:

``````for (auto i = array.begin(); i != array.end(); ++i)
cout << *i; // remember to use the dereferencing operator``````

So what we did here is we created a iterator pointer to the start of the array, and as long as the iterator doesn’t equal the end of the array, then we would increment it by one. Now you might be wondering two things.

Wait, shouldn’t the pointer stop before it reaches the end of the array because of the condition: `i != array.end()`?
Well, no. Because `array.end()` doesn’t point to the last element, but rather the end of the last element. I honestly don’t know how that works, but yeah, it works!
Wut just happened?
I’m assuming that most of you are thinking of this right now. Don’t worry, that’s perfectly normal to experience. That was me when I first learned about this too. Let me draw a picture below.

``````_____________     ______________       _____________
FIRST ELEMENT     SECOND ELEMENT      THIRD ELEMENT

array.begin()                                          array.end()``````

Notice how `array.end()` points at the very very end of the array. So with this condition: `i != array.end()`, you are saying that as long as `i` doesn’t become `array.end()`, then print out an element.

Hopefully this helps. Just play around with the for loop to see what works and hopefully it’ll become easier to understand soon.

Oh, a couple more things. First, I’m going to show you a handy trick I learned. We’re going to use templates for this, so if you don’t know what templates are, then just know what the function outputs.

``````template<typename T>
void DisplayContents(T container)
{
for (auto i = container.begin(); i != container.end(); ++i)
cout << *i << “ “;
}``````

As you can see, this template function can print out the contents of any container! This will definitely come in handy. At the very least, know that this function will print the contents of a container.

Oh, and because of @Highwayman said that long tutorials are cool, and @ipastrano wants a in depth section about them, let’s talk about one more thing concerning iterators. Constant iterators.

So the iterators you’ve seen so far are one of two ways:

`container<type>::iterator element = container.begin();`
`auto element = container.begin();`

But, since constants exist, and it’s considered “good programming practice”, however the last time I used the `const` keyword was like never, let’s take a look at what a constant iterator looks like.

``````container<type>::iterator element = container.begin(); // normal iterator
container<type>::const_iterator element = container.cbegin(); // notice the use of ‘.cbegin();’
auto element = container.cbegin(); // you can also just use ‘auto’``````

As you probably guess, `.cbegin()` stands for “constant begin”. Same for `.cend()`. Now constant iterators are for when you just want to access an element without modifying it. But if you want to modify elements, then don't use const. Let’s take a look at an example.

Oh, and again, you can use a random access operator for vectors without using iterators. But since vectors are like the only container you’ve learned so far, we’re going to use them as an example.

``````vector<int> intVector = { 1, 2, 3, 4, 5 };
for (auto i = intVector.cbegin(); i != intVector.cend(); ++i)
cout << *i << “ “;``````

As you can see, here I’m just displaying the elements of a container, so I used const. But it really doesn’t matter cause no one cares about `const`.

Learn more about the basics of iterators here, and some more things you can do with them here.

Anyway, let’s move on!

# Lists

A list is a list. All you need to know. Moving on. Next section! Just kidding.

`std::list`

A list is a little different from a standard array. Think of a list as a group of nodes. Each node contains an element, just like any other array, but it also contains two “pointers”. Each pointer links the current node to the next node. I like to call them links.

Let’s visualize it:

----- LINK | element | LINK ----- LINK | element | LINK ----- LINK | element | LINK -----

As you can see, there are three nodes in our list. Each contains an element, and two links. And each link points to the next node.

So what are the benefits to using a list? So remember how vectors only support insertion and removal at the end, and deques support insertion and removal at both ends? Well a list supports insertions everywhere! Start, end, middle, top, bottom, inside, and outside! But a downside to using lists is that searching elements is slower than a vector or deque. Let’s recap the benefits of all three containers just to keep things on track.

Vector - insertion and removal at the end
Deque - insertion and removal at both ends
List - insertion and removal wherever, but slower search times

So use lists when you have frequent insertions in the middle, but use vectors or deques when you have frequent searches.

Let’s take a look at what we can do with a list.

``````#include <list> // don’t forget the header!

list<int> intList;
list<char> charList = { ‘d’, ‘y’, ‘n’, ‘a’, ‘m’, ‘i’, ‘c’ };

charList.push_back(‘s’); // same as vector!
charList.pop_front(); // same as deque!``````

As you can see, lists have similar functions as vectors. But be careful! Lists aren’t organized, so you can’t randomly search up elements. For vectors, you can use `intVector`, but you can’t do that with a list! You have to use a STL iterator!

``````list<int> intList = { 1, 2, 3, 4, 5 };

// list<int>::iterator element = intList.begin();
auto element = intList.begin();
advance(element, 2);

cout << *element;``````

As you can see, we created a pointer, then advanced that pointer 2 places. In fact, `advance()` is just a fancy way of doing:

``````++element;
++element;``````

Now let’s look at insertion and removal.

``````list<char> name = { ‘s’, ‘q’, ‘i’, ‘d’, ‘s’ };

auto element = name.begin();
advance(element, 2);

name.insert(element, ‘u’);
name.erase(--name.end());``````

So the third and fourth lines create a pointer that points two the second element, and then we added a character to the list. Now the last line showed how to remove an element. Notice how we used `.end()`. But remember, `.end()` does not point to the last element, it points to the end of the last element. So we have to decrement it so that it points to the last element.

Notice how you can’t do this: `name.erase(‘d’)`. That’s because most STL methods have pointer parameters. And yes, `.begin()` and `.end()` are pointers.

Well what other things can we do with a list?

``````intList.reverse();
intList.sort(); // ascending order``````

Those two methods do exactly what you’d expect. `.sort()` sorts the list in ascending order, and `.reverse()` erases all elements and crashes your program entirely.

If you’re still confused, or just want some more examples, check out this link.

`std::forward_list`

It’s basically like a list, but in one direction.

----- LINK | element | LINK ----- LINK | element | LINK ----- LINK | element | LINK |

So you can do everything you do with a list to a forward list, but only in one direction. It helps optimize for storage and memory consumption. You can read more about it here.

``````#include <forward_list>

forward_list<int> flist = { 2, 2, 3, 4, 5 };

flist.pop_front();
flist.push_front(1);``````

And yeah, that’s basically it. Everything else is the same.
Sets and Multisets
Now, let’s talk about associative containers! Before, you learned about sequential containers, but associative containers are a little different. They assign each value a key, and that means that they automatically sort each element. This also means that they have way faster searches, but slow insertions.

Sequential - slow searches but fast insertions
Associative - fast searches but slow insertions

Both sets and multisets use a binary tree system on the inside to facilitate quick searches. I personally have never seen what trees looked on the inside, so I actually don’t know how this works. I’m guessing maybe some rings or some moss or something. I dunno.

Oh, and I forgot to mention. So associative containers store keys, and those keys have a value. Well, sets and multisets are different in that they store keys. And the keys are the values. You’ll see the difference when we look at maps.

`std::set` and `std::multiset`

Sets store values. But the values can’t be a duplicate. If so, set does ignore it. The values are also sorted automagically on insertion (ascending). Multiset works the same way, but it can store duplicate values.

``````#include <set> // works for both sets and multisets

set<int> intSet = { 1, 2, 3, 4, 5, 5 }; // the second 5 is ignored
multiset<int> intmSet = { 1, 2, 3, 4, 5, 5 };

set<int> sortThis = { 4, 2, 6, 8, 3, 5, 7 }; // don’t worry, this is all sorted automatically

intSet.insert(6); // inserting a value

cout << “there are” << multiset.count(5) << “ fives in the multiset”;``````

As you can see, we used the method `.insert()` to insert a value. The value is inserted on insertion, so you don’t have to specify a place. We also used `.count()` to count how many fives there were in the multiset. It should return a 2.

Let’s check out what else we can do with sets and multisets.

``````set<int> intSet = { 1, 2, 3, 4, 5 };

auto findElement = intSet.find(4);

if (findElement != intSet.end())
cout << “The element: “ << *findElement << “ was found!”; // don’t forget to dereference it!``````

As you can see here, we used the `.find()` method to search for an element. The way it works is it first points to the first element (and yes, it’s a pointer), and checks to see if it’s a 5. If not, then it points to the second element, and so forth. It will keep searching until it finds the element, or reaches the end of the array. That’s why we used a if statement to check if the element was found or not. And don’t forget that `.find()` returns a pointer. So we have to use the dereferencing operator to reverse the point to see the actual value.

In a multiset with duplicate values, `.find()` will point to the first one.

What about erasing elements?

``````set<int> intSet = { 1, 2, 3 };
intSet.erase(3); // you can erase a element using the value like this,
intSet.erase(intSet.begin()); // or using a pointer like this``````

`std::unordered_set` and `std::unordered_multiset`

Now the unordered variants of set and multiset are basically the same as the regular ones, except for the fact that the elements aren’t ordered on insertion. This means that unordered sets have even faster search times (constant) than sets regular sets (log). But other than that, they’re practically the same.

Let’s take a look at their syntax.

``````#include <unordered_set> // same for unordered multiset

unordered_set<int> uSet = { 2, 5, 4, 8 }; // elements aren’t sorted;
unordered_multiset<int> umSet = { 2, 2, 6, 5, 7, 5, 8 }; // duplicates possible``````

You can learn more about both the regular sets and unordered sets here.

# Maps and Multimaps

One of the most versatile containers out there. Maps store a key, and a value. Exactly like a dictionary. And once again, the difference between maps and multimaps is that the latter allows for duplicate values (don’t get confused with values, you can have duplicate values even in a map).

`std::maps` and `std::multimap`

``````#include <map> // same for mulitmap
#include <string> // let’s do an example with some strings :)

map<int, string> intToString; // sorry, no list initialization here :(

intToString.insert(make_pair(1, “Hello”));
intToString.insert_make_pair(2, “World!”));
intToString.insert(makePair(3, “Hello World!”));
intToString = “Hello Planet!”; // you could also you an array-like syntax if you wish

multimap<int, float> intToFloat;

intToFloat.insert(makePair(1, 3.14));
intToFloat.insert(makePair(1, 1.61)); // can store duplicates
intToFloat.insert(makePair(3, 2.71));``````

As you can see, we paired up a key and a value using `.makePair()`, and then inserted them into the map. The map will now contains:

``````1   Hello
2   World!
3   Hello World!
4   Hello Planet!``````

What are some things we can do with maps?

``````multimap<int, int> intintmap; // don’t be surprised by the creative name

intintmap.insert(make_pair(1, 20));
intintmap.insert(make_pair(2, 30));
intintmap.insert(make_pair(2, 40));
intintmap.insert(make_pair(2, 40));

cout << “there are “ << intintmap.count(2) << “ values that have a key of 2”;``````

Just a note, `.count()` when used on a map finds keys, not values. Let’s take a look now at some find operations.

``````map<int, int> intMap;

intMap.insert(makePair(5, 25));
intMap.insert(make_pair(6, 36));
intMap.insert(make_pair(9, 81));

auto findKey = intMap.find(5); // finds the key, not the value

if (findKey != intMap.end()) // checking to see if key is found
cout << “the key “ << findKey->first << “ has a value of “ << findKey->second;``````

Okay, let’s break this down. So first we created a map. Then we added some elements to it. But now we want to access the elements, so remember, we have to use an iterator. Instead of using `auto`, I could have used `map<int, int>::iterator`, but I chose to use `auto` instead.

Then I used the `.find()` method to find a certain key. And then I just printed the values. `->first` is the key, and `->second` is the value. Remember, we’re dealing with pointers here, so we have to use `->`. Also, it’s always good practice to check whether or not the value actually has been found or not, as you can see with the if statement.

If you want to display all the elements with a certain key for multimaps, then it gets a little complicated.

``````auto findPair = multimap.find(key); // find first key

int numberOfPairs = multimap.count(key); // count how many times that key appears

for (int i = 0; i < numberOfPairs; ++i)
{
cout << “key “ << findPair->first << “ has a value of “ << findPair->second;
++findPair; // point findPair to the next key
}``````

So what we did here was create a variable called `findPair` that finds a specific key. Then we counted how many times that specific key appeared in the map, and used that in our for loop. Then we just displayed the key and value.

Also, take a look at this line: `++findPair`. That does not go to the next key, but rather the next key with the specific value. Because remember, we set `findPair` as `multimap.find(key)`, so everytime we increment it, we are just pointing it to the next key with that value.

Time to erase?

``````	auto erasePair = multimap.find(key);
multimap.erase(erasePair); // deletes first instance of key

multimap.erase(key); // deletes all instances of key``````

And it would work as you would expect on a regular map.

`std::unordered_maps` and `std::unordered_multimap`

Now the same as set, the unordered variants of map and multimap are basically the same as the regular ones, except that the elements aren’t ordered on insertion. This means that unordered maps have even faster search times (constant) than sets regular maps (log). But other than that, they’re the exact same.

``````#include <unordered_map>

unordered_map<int, int> unorderedMAP;
unorderedMAP.insert(make_pair(10, 100));``````

For more information on maps, check this out.

## Conclusion

Summary

Here’s a list of everything we covered (referenced from Sams Teach Yourself).

Vectors (sequential)
Fast insertion at the end (constant time)
Supports random access operator (vector and deque are the only ones)
Slow searches (linear), and resizing can result in performance loss

Deque (sequential)
Same benefits with vector, but also supports insertion at the front
Same downsides as vector

List (sequential)
Constant time insertion wherever
Linear search times, and may sometimes be slower than vectors and deques

Forward List (sequential)
Same with list, but operates in one direction
Can cut down on memory usage

Set and Multiset (associative)
Operates in a similar fashion to sequential containers
Faster search times than sequential containers (log)
Slower insertion times than sequential containers (linear)

Unordered Set and Unordered Multiset (associative)
Even faster search times (constant) than set and multiset
Has constant time insertion, but elements are weakly linked

Map and Multimap (associative)
Same search times as set (log)
Faster search times than sequential containers (log)
Slow insertion times (linear)

Unordered Map and Unordered Multimap
Ever faster search times (constant) than map and multimap
Has constant time insertion, but elements are weakly linked

And that’s it! You made it to the end! Hopefully this tutorial was really helpful to you guys, and you might have learned something new.

And sorry for not covering everything. I know there were some suggestions for `std::tuple` and `std::any`, but I don’t have enough time or space to cover them here in this tutorial.

Oh, and I might be doing a part 2 soon (depends on how this tutorial does). It’ll talk about some of the same concepts here, but in a more advanced way. Things that I have in mind for part 2 (not in order):

Time Complexity
Strings
STL Adaptive Containers
More STL Containers
More STL Algorithms
Functors and Lambdas
STL and Bit Flags

Or perhaps I could create a tutorial on something less complicated (but still related to STL in some way), like classes and objects or templates or pointers or something along those lines. And don’t be afraid to comment below some concepts you would like to be seen in a tutorial. I’m always open to new ideas!

With all that being said, please share your thoughts and questions down in the comments, and don’t forget to leave a like!

Sources

##### Comments
hotnewtop
SilentShadowBla (552)

Nice job! this is one of the best C++ tutorials I have ever seen!

ChimaNwosu1 (7)

Nice! Learned a lot!

DynamicSquid (4893)

@ChimaNwosu1 Cool! Glad I helped someone

Highwayman (1483)

# YAY! It’s Here!

DynamicSquid (4893)

@Highwayman There's still so many things I have to fix since I did this on Google Docs and the format is messed up

Highwayman (1483)

@DynamicSquid yeah, there are some thing but that’s small, I’d say. I’m just happy it’s here :P

DynamicSquid (4893)

@Highwayman I should probably tell everyone in my first post that it's finished

Highwayman (1483)

@DynamicSquid yeah, definitely, we were all pretty excited I’d say :P

psina19 (0)

Anybody here who can help me ?

xxpertHacker (935)

Well... I guess I finally figured out how to truly use templates:

``````#include <iostream>

template<const unsigned long long X = 0ull>
struct Factorial
{
constexpr static const unsigned long long value = X * Factorial<X-1ull>::value;
};

template<>
struct Factorial<0ull>
{
constexpr static inline const unsigned long long value = 1ull;
};

int main()
{
std::wcout << Factorial<5>::value;
} // Run this on Repl``````
xxpertHacker (935)

You must’ve gotten a higher score on that bored index of yours than I did, huh? I'm incredibly bored and made a tutorial too, but this... this is good, you have way too much time on your hands. But off I go, I gotta learn WebSockets without a teacher, since we’re in the same situation!