Basic Templates

Basic Templates

Requirements:
Linux Distribution
g++
any text editor

My Setup:
Debian 10
g++ version 6.3.0
pluma

In this tutorial, I will be introducing you to the concept of templates. What
are templates ? Templates are a form of generic programming which allows you to
generate code for multiple types. The one thing to remember, is when defining
templates , your template functions must be declared in an include file . So
what exactly does this mean? Let me give a very basic example:


template<typename t>
t add(t x, t y){
  return x+y;
}

Ok so imagine this code was somewhere in a header file, and you wanted to use
this to add two of the same type of variable together. It could be any variable
that operator+() supports. So in my main.cpp file you will see:

#include "add.hpp" //whatever the name of the file is

int main(int argc, char *argv[]){

  float a = 2.53f; // Use "f" at the end for a float literal
  float b = 4.81f;

  int x = 125;
  int y = 250;

  double foo = 37.3562L; //can use "L" or "l" for literal
  double bar = 26.4341l;

  std::cout << "a+b = " << add<float>(a,b) << std::endl;
  std::cout << "x+y = " << add<int>(x,y) << std::endl;
  std::cout << "foo + bar = " << add<double>(foo,bar) << std::endl;

  return 0;
}

Looking at this example, you can assume the compiler created an add function
that took in 2 parameters and returned a type based on what was placed between
the greater than and less than signs. I am gonna give you an example from my
own game engine project, and within the next few tutorials, i will be going over
my own thought processes to improve the code. But lets look at it first:

#ifndef VECTOR2_HPP_
#define VECTOR2_HPP_

#include <iostream>
#include <string>

namespace libre{

	namespace math{

    /**
     *@brief internalv2
     * a simplification for opengl usage. can easily call getInternal().i_x or getInternal().i_y
     */
    template <typename t>
    struct internalv2{
        t i_x;
        t i_y;

        internalv2(){}
        internalv2(t x, t y):i_x(x),i_y(y){}
    };

         /**
         *@brief Vector2 Class
         *
         * A generic class to hold a Vector of 2 of the same type of data;
         *
         * DataType: x
         * DataType: y
         *
         * Notes : As a rule of Templates, All functionality is written in this header
         *        Const Compatible
         */

		template <typename t>
		class Vector2{

		private:
		t m_x;
		t m_y;

		public:
        Vector2(){}
        Vector2(const t& x,const t& y);
        Vector2(const internalv2<t> &vec);
		Vector2(const Vector2& copy);

		t& getX();
		t X()const;
		t& getY();
		t Y()const;

		void setX(t x);
		void setY(t y);

        internalv2<t> getInternal(){return internalv2<t>(m_x,m_y);}

		Vector2<t> add(const Vector2<t> &other);
		Vector2<t> sub(const Vector2<t> &other);
		Vector2<t> multiply(const Vector2<t> &other);
        Vector2<t> multiply(const t &scalar);
		Vector2<t> divide(const Vector2<t> &other);

		Vector2<t> operator=(Vector2 right);
		Vector2<t> operator+(Vector2 right);
		Vector2<t> operator-(Vector2 right);
		Vector2<t> operator*(Vector2 right);
        Vector2<t> operator*(t right);
		Vector2<t> operator/(Vector2 right);

		bool operator==(Vector2<t> right);
		bool operator!=(Vector2<t> right);

		const char *toString();

		};

		template <typename t>
		Vector2<t>::Vector2(const t&x, const t&y){
				this->m_x = x;
            this->m_y = y;
        }
        template <typename t>
        Vector2<t>::Vector2(const internalv2<t> &vec)
        {
            setX(vec.i_x);
            setY(vec.i_y);

        }
		template <typename t>
		Vector2<t>::Vector2(const Vector2<t>& copy){
			this->m_x = copy.X();
			this->m_y = copy.Y();
		}
		template <typename t>
		t& Vector2<t>::getX(){
			return this->m_x;
		}
		template <typename t>
		t Vector2<t>::X()const{
			return this->m_x;
		}
		template <typename t>
		t& Vector2<t>::getY(){
			return this->m_y;
		}
		template <typename t>
		t Vector2<t>::Y()const{
			return this->m_y;
		}

		template <typename t>
		void Vector2<t>::setX(t x){
			this->m_x = x;
		}

		template <typename t>
		void Vector2<t>::setY(t y){
			this->m_y = y;
		}
		template <typename t>
		Vector2<t> Vector2<t>::add(const Vector2<t> &other){
			Vector2<t> vec(this->m_x + other.X(), this->m_y + other.Y());
			return vec;
		}
		template <typename t>
		Vector2<t> Vector2<t>::sub(const Vector2<t> &other){
			Vector2<t> vec(this->m_x - other.X(), this->m_y - other.Y());
			return vec;
		}
		template <typename t>
		Vector2<t> Vector2<t>::multiply(const Vector2<t> &other){
			Vector2<t> vec(this->m_x * other.X(), this->m_y * other.Y());
			return vec;
		}
        template <typename t>
        Vector2<t> Vector2<t>::multiply(const t &scalar){
            Vector2<t> vec(this->m_x * scalar, this->m_y * scalar);
            return vec;
        }
		template <typename t>
		Vector2<t> Vector2<t>::divide(const Vector2<t> &other){
			Vector2<t> vec(this->m_x / other.X(), this->m_y / other.Y());
			return vec;
		}

		template <typename t>
		Vector2<t> Vector2<t>::operator=(Vector2 right){
			return Vector2<t>(right);
		}
		template <typename t>
		Vector2<t> Vector2<t>::operator+(Vector2 right){
			return this->add(right);
		}
		template <typename t>
		Vector2<t> Vector2<t>::operator-(Vector2 right){
			return this->sub(right);
		}
		template <typename t>
		Vector2<t> Vector2<t>::operator*(Vector2 right){
            return this->multiply(right);
        }
        template <typename t>
        Vector2<t> Vector2<t>::operator*(t right)
        {
            this->m_x * right;
            this->m_y * right;
        }
		template <typename t>
		Vector2<t> Vector2<t>::operator/(Vector2 right){
			return this->divide(right);
		}

		template <typename t>
		bool Vector2<t>::operator==(Vector2<t> right){
			return (this->m_x == right->X()) && (this->m_y == right->Y());
		}
		template <typename t>
		bool Vector2<t>::operator!=(Vector2<t> right){
						return (this->m_x != right->X()) || (this->m_y != right->Y());
		}

		template <typename t>
		const char * Vector2<t>::toString(){

            std::string vec2String("X: " + std::to_string(this->m_x));
            vec2String.append(",Y: "+std::to_string(this->m_y));

            return vec2String.c_str();
		}
	}//namespace math
}//namespace libre

#endif //vector2.h

So this is a Vector2 class I use that has basic functions it can do to either
each other, or the data type specified. One idea that pops into my head is using
this to describe a basic versioning system, using unsigned ints. Another could
be map sizes, tile sizes. But also it could be 2d animation, using floats for
precision, or doubles. The main point is that I can use this class to
create objects with different variables based on the type specified.

Leave a Reply