1. If you pass an expression as argument to the CIRCLE_AREA the expression would end up being evaluated twice.
For example
|
double a = CIRCLE_AREA(f());
|
would expand to
|
double a = ((PI) * (f()) * (f())) ;
|
which might be a problem if f() has side effects that you only want to happen once or if f() is slow so that you don't want to call it more often than necessary.
If you instead write
|
double a = circleArea(f());
|
then f() would only be evaluated once.
2. If you pass an argument to the circleArea function that is not a double it will try to implicitly convert the argument to a double. If that fails you will get a compilation error.
The CIRCLE_AREA macro will not type check its argument. Instead it will just expand the macro code and give a compilation error if the * operator cannot be performed on the types involved. The downsides of this is not so easy to see in this situation because all the built-in numeric types can be implicitly converted to each other, and few other types support the binary * operator, but sometimes this lack of type checking can lead to code that still compiles but doesn't do what you expect.
Let's consider the following macro instead:
|
#define SUM(a, b) ((a) + (b))
|
If you passed two integers as arguments it would return the expected result
1 2 3
|
int a = 1;
int b = 2;
std::cout << SUM(a, b) << "\n"; // prints "3"
|
but if you accidentally passed two std::strings it would instead do string concatenation.
1 2 3
|
std::string a = "1";
std::string b = "2";
std::cout << SUM(a, b) << "\n"; // prints "12"
|
or if you called it with a string literal (i.e. char*) and an integer (perhaps believing you could use it for string concatenation) it would instead do pointer arithmetic on the char pointer.
|
std::cout << SUM("Hello", 2) << "\n"; // prints "llo"
|
If you instead had used functions you wouldn't have ran into these issues because either the argument is implicitly converted to the expected type or it is rejected all together.
1 2 3 4
|
int sum(int a, int b)
{
return a + b;
}
|
1 2 3
|
int a = 1;
int b = 2;
std::cout << sum(a, b) << "\n"; // prints "3"
|
1 2 3
|
std::string a = "1";
std::string b = "2";
std::cout << sum(a, b) << "\n"; // error (no implicit conversion from std::string to int)
|
|
std::cout << sum("Hello", 2) << "\n"; // error (no implicit conversion from char* to int)
|
1 2 3 4
|
std::string concat(std::string a, std::string b)
{
return a + b;
}
|
1 2 3
|
int a = 1;
int b = 2;
std::cout << concat(a, b) << "\n"; // error (no implicit conversion from int to std::string)
|
1 2 3
|
std::string a = "1";
std::string b = "2";
std::cout << concat(a, b) << "\n"; // prints "12"
|
|
std::cout << concat("Hello", 2) << "\n"; // error (no implicit conversion from int to std::string)
|