The difference between macros and templates is that the former are a pre-processor tool and the latter a language tool.
Translation phases.
In C++ the code goes through nine phases to generate an executable file:
The characters in the code are adjusted to match the characters accepted by the standard.
Multiline statements are put together on a single line.
Comments are removed.
The preprocessor is executed .
Characters in character or string literals are passed to the system encoding.
Adjacent string literals are concatenated.
It compiles .
Template instances that have been instantiated are examined .
All components are linked in the executable file.
Macros are " executed " in phase 4, templates in phase 7. A macro works just like a word processor find-replace, suppose we have this code:
#include <iostream>
#define UNO 11
#define DOS UNO + UNO
#define TRES 333
#define PATATA(A, B) A - B
int main()
{
#ifdef DEBUG
std::cout << "Debug";
#else
std::cout << "Release";
#endif
std::cout << PATATA(UNO, DOS) + PATATA(DOS, TRES);
return 0;
}
In phase 4, the preprocessor is executed, which:
Will replace with the entire #include <iostream>file .iostream
Everything in conditionals ( #ifdef, #else, #endif) will be removed or kept depending on the condition.
The symbols of the "macros" will be searched for and replaced (as a search-replace) with the value they represent, so the previous code would look like this:
Aquí está todo el archivo iostream
...
...
...
int main()
{
std::cout << "Release";
std::cout << 11 - 11 + 11 + 11 + 11 - 333;
return 0;
}
And that is the code that is finally compiled in phase 7. Knowing this, your answers are:
At compile time, are there any differences regarding build performance?
The macros hardly affect the compile time since they are not part of the compilation (phase 7) itself. They have an impact on the total translation time, but it is small; What will affect the most in time will be the inclusions.
Templates have a considerable impact on compile time, in each translation unit they will be instantiated and re-compiled even though they have been instantiated and compiled in other translation units.
When the program is run, what are the differences?
When the program is executed, what was compiled is obviously executed; so the question doesn't make sense: whether templates were compiled or a program containing macros was compiled, the difference will obviously be the compiled code.
At compile time, are there any differences regarding build performance?
Because templates can be called recursively, compiling templates can take longer to compile.
When the program is run, what are the differences?
When it runs...none. Macros or templates do not travel to the final program, but rather machine instructions.
The difference is at the source code level and during the build phase.
Macros are something inherited from C and, because of this, they are elements with certain deficiencies.
1. They do not have typing
The macro is handled by the preprocessor, which is the first element that comes into play during compilation. The preprocessor doesn't listen to C++ syntax... it just listens , the preprocessor directives, and nothing else. The compiler, which does type checking, comes into play next, but it may already be late.
Let's assume a simple and seemingly innocuous macro:
#define MIN(a,b) a < b ? a : b
Nothing special, it returns the largest element of two that we pass as a parameter:
std::cout << MIN(5,8); // Imprime 5
Now, since it is not typed, nothing prevents us from doing the following:
std::cout << MIN("abc","def");
What will you print now? This time the macro will be replaced with:
std::cout << "abc" < "def" ? "abc" : "def";
And by now we should know that as long "abc"as they "def"are pointers to type char and that what we are comparing here are memory addresses instead of values, then depending on how the compiler works, the example will be able to print either of the two strings. what's cool? Well, the truth is that no.
2. They are dangerous
To illustrate this point we are going to reuse the macro from the first point.
What would happen before this sequence?
int a = 10;
int b = 5;
std::cout << MIN(a++,b++);
If we exploit the macro we will have the following:
int a = 10;
int b = 5;
std::cout << a++ < b++ ? a++ : b++;
And here we are already beginning to move on slippery ground because it turns out that we are facing an indeterminate behavior, that is, it will depend on the compiler to give us one result or another. To see it more graphically, the previous code could end up converted into this one:
int a = 10;
int b = 5;
bool resultado = a < b;
a++;
b++;
if( resultado )
std::cout << a;
else
std::cout << b;
a++;
b++;
Or also in this other one;
int a = 10;
int b = 5;
bool resultado = a < b;
if( resultado )
std::cout << a;
else
std::cout << b;
a++;
a++;
b++;
b++;
And it is easy to see that each code prints a different result.
3. Cannot be debugged
Code generated by macros cannot be debugged and breakpoints cannot be placed in such code.
That is, macros complicate code debugging tasks.
4. They don't work with intellisense
Modern IDEs have intellisense, a utility that greatly simplifies the life of the programmer since it gives you information about the code (type of a variable, members of a class, etc...) while you write... and macros are perfect for bring down the system.
If you have a macro to generate classes or functions:
#define NEW_CLASS(Name,Type) \
class Name \
{ \
Type var; \
public: \
Type Get() const \
{ return var; } \
\
void Set(Type value) \
{ var = value; } \
};
And you create a couple of classes:
NEW_CLASS(A,int);
NEW_CLASS(B,float);
You can use them in your program without problems:
int main()
{
A a;
B b;
a.Set(10);
b.Set(45,6);
std::cout << a.Get() << ' ' << b.Get();
}
Buuuut forget about intellisense working. At best, it will tell you the code that the macro generates when it is processed... but little else. It's up to you to learn or review the macro to know the members of Aand Beach time you want to use those classes.
Summary
Templates, on the other hand, do not have these problems so they would be the option to choose against macros whenever possible.
The difference between macros and templates is that the former are a pre-processor tool and the latter a language tool.
Translation phases.
In C++ the code goes through nine phases to generate an executable file:
Macros are " executed " in phase 4, templates in phase 7. A macro works just like a word processor find-replace, suppose we have this code:
In phase 4, the preprocessor is executed, which:
#include <iostream>
file .iostream
#ifdef
,#else
,#endif
) will be removed or kept depending on the condition.And that is the code that is finally compiled in phase 7. Knowing this, your answers are:
The macros hardly affect the compile time since they are not part of the compilation (phase 7) itself. They have an impact on the total translation time, but it is small; What will affect the most in time will be the inclusions.
Templates have a considerable impact on compile time, in each translation unit they will be instantiated and re-compiled even though they have been instantiated and compiled in other translation units.
When the program is executed, what was compiled is obviously executed; so the question doesn't make sense: whether templates were compiled or a program containing macros was compiled, the difference will obviously be the compiled code.
Before answering, I recommend reading this other question: constexpr vs macro vs inline function
Because templates can be called recursively, compiling templates can take longer to compile.
When it runs...none. Macros or templates do not travel to the final program, but rather machine instructions.
The difference is at the source code level and during the build phase.
Macros are something inherited from C and, because of this, they are elements with certain deficiencies.
1. They do not have typing
The macro is handled by the preprocessor, which is the first element that comes into play during compilation. The preprocessor doesn't listen to C++ syntax... it just listens , the preprocessor directives, and nothing else. The compiler, which does type checking, comes into play next, but it may already be late.
Let's assume a simple and seemingly innocuous macro:
Nothing special, it returns the largest element of two that we pass as a parameter:
Now, since it is not typed, nothing prevents us from doing the following:
What will you print now? This time the macro will be replaced with:
And by now we should know that as long
"abc"
as they"def"
are pointers to type char and that what we are comparing here are memory addresses instead of values, then depending on how the compiler works, the example will be able to print either of the two strings. what's cool? Well, the truth is that no.2. They are dangerous
To illustrate this point we are going to reuse the macro from the first point.
What would happen before this sequence?
If we exploit the macro we will have the following:
And here we are already beginning to move on slippery ground because it turns out that we are facing an indeterminate behavior, that is, it will depend on the compiler to give us one result or another. To see it more graphically, the previous code could end up converted into this one:
Or also in this other one;
And it is easy to see that each code prints a different result.
3. Cannot be debugged
Code generated by macros cannot be debugged and breakpoints cannot be placed in such code.
That is, macros complicate code debugging tasks.
4. They don't work with intellisense
Modern IDEs have intellisense, a utility that greatly simplifies the life of the programmer since it gives you information about the code (type of a variable, members of a class, etc...) while you write... and macros are perfect for bring down the system.
If you have a macro to generate classes or functions:
And you create a couple of classes:
You can use them in your program without problems:
Buuuut forget about intellisense working. At best, it will tell you the code that the macro generates when it is processed... but little else. It's up to you to learn or review the macro to know the members of
A
andB
each time you want to use those classes.Summary
Templates, on the other hand, do not have these problems so they would be the option to choose against macros whenever possible.