There is some differences between them, lets consider these add functions:
#define Add1(x,y) (x+y)int Add2(int x,int y){ return x+y;}inline int Add3(int x,int y){ return x+y;}template<typename T>T Add4(T x,T y){ return x+y;}template<typename T>inline T Add5(T x,T y){ return x+y;}template<typename T,typename T2>T Add6(T x,T2 y){ return x+y;}template<typename T,typename T2>inline T Add7(T x,T2 y){ return x+y;}template<typename T,typename T2>T Add8(T x,T2 y){ return x+static_cast<T>(y);}template<typename T,typename T2>inline T Add9(T x,T2 y){ return x+static_cast<T>(y);}
Ok we have 9 Add functions, they all add 2 types. The first is the most simple, just a preprocessor function, the preprocessor should be seperate from the C++ compiler so first the preprocessor runs the code and generates code. So imagine this code:
The preprocessor will start by generating this code:
The problem with this is that it is not typesafe.
The second and third add function is a standard function taking an int. So this restricts the program to only pass integers or at least requires them to convert to integer, so if you have a short (and sizeof(short)!=sizeof(int) which it normally is) then the short will just gets converted without telling you and this could give performance problems if done a lot, from short to integer ain't very bad though. The difference between the second and third is that the third is "inline" which means the compiler tries to put the code "in the line it was called from", so it will try to generate the same code as the preprocessor function. The second is not inlined which means that the program needs to jump to the function and get back again which probably takes much longer than the actual addition, so this is not how you should do it. Note that inline is just a suggestion so the compiler can choose for itself, but any decent compiler should inline both the second and third add function since it is so small.
The fourth and fifth is the same as the second and third, just templated so it can take more types and if you pass another type like a short you don't need to convert it to an integer since it will just perform a short addition.
The sixth and seventh is a little tricky, they take too different (they can also be equal) types which means you can pass a float and a double for example and you don't need to convert one to the other (unless the addition requires it). It only works if we have an addition operator taking T and T2 or we have an implicit conversion from T2 to T.
The eighth and nineth is just like the sixth and seventh they just tries to convert from T2 to T explicitely, so it will probably work with more types, but can be a bit slower since if the types aren't equal we will do the conversion even though an addition operator can take T and T2 we will also convert even though there might be a loss of data, or precision.
We could also have created add functions returning T2 instead of T, but that would just be too complicated. We could also make a T3 which were the return type.