## Passing an enum by parameter

Author: Chloé Lourseyre

Let’s say you have a function you have to call using two parameters :

• The first parameter is a configuration option symbolized by an enum. Like the “mode of use” of your function.
• The second parameter is a true numeral parameter.

Let’s use the following example to represent that :

```#include <iostream>

// Enum describing the mode used in the following function
enum class ChangeMode
{
Before,
After
};

// Function that squares a value and increases it (wether before or after), then prints the result
void increase_and_square(const ChangeMode& m, int v)
{
if (m == ChangeMode::Before)
++v;

v = v*v;

if (m == ChangeMode::After)
++v;

std::cout << v << std::endl;
}

// main function
int main()
{
const int a = 42;
increase_and_square(ChangeMode::Before, a);
increase_and_square(ChangeMode::After, a);
}
```

In this example, we perform slightly different operation depending on the “mode” used. This is a fairly common behavior that can occur in may different forms.

However, implemented as it is there is not the most optimized way to do this. A best way to obtain the same result is to use the `ChangeMode` as a template instead of a plain parameter.

Like this :

```#include <iostream>

// Enum describing the mode used in the following function
enum class ChangeMode
{
Before,
After
};

// Function that squares a value and increases it (wether before or after), then prints the result
template<ChangeMode m>
void increase_and_square(int v)
{
if (m == ChangeMode::Before)
++v;

v = v*v;

if (m == ChangeMode::After)
++v;

std::cout << v << std::endl;
}

// main function
int main()
{
const int a = 42;
increase_and_square<ChangeMode::Before>(a);
increase_and_square<ChangeMode::After>(a);
}
```

Impementing the function like is actually better in every way :

• Operations done at compile time : of course, and as the main advantage of using templates, we evaluate more expressions a compile time here, saving run time.
• Compiler optimization : since the compiler will be able to evaluate more things at compile time, it will be able to optimize the code, effectively discarding the `if` statements.
• Executable size : more impressive, the executable will be smaller with the templated version. This is so because the fact that we discard the if statement actually greatly reduce the size of the functions.

To illustrate this, here is the template instanciation the compiler generates :

```void increase_and_square<ChangeMode::Before>(int v)
{
++v;
v = v*v;
std::cout << v << std::endl;
}

void increase_and_square<ChangeMode::After>(int v)
{
v = v*v;
++v;
std::cout << v << std::endl;
}
```

These are way simpler functions that the big bulky one above.

If you are not convinced, here is the number of assembly instructions the compiler generates (I used Compiler Explorer (godbolt.org) with clang as compiler and `--std=c++20 -O3` as compiler options).

123

#### Template

76

The template version is clearly better, faster, prettier.

## Perk : double default values

Using the template version of this code also provides another perk : the ability to give a default value to your mode and to your parameter.

Since default values are decorrelated for templates and parameters, you can write this :

```#include <iostream>

// Enum describing the mode used in the following function
enum class ChangeMode
{
Before,
After
};

// Function that squares a value and increases it (wether before or after), then prints the result
template<ChangeMode m=ChangeMode::Before>
void increase_and_square(int v = 2)
{
if (m == ChangeMode::Before)
++v;

v = v*v;

if (m == ChangeMode::After)
++v;

std::cout << v << std::endl;
}

int main()
{
const int a = 42;
increase_and_square(a);
increase_and_square<ChangeMode::After>();
increase_and_square();
}
```

This is interesting because the mode and the parameter actually have different semantic meanings, thus it is only logical that they have separate behavior.

## Limitations

Why does this work ? Because the “mode” we template is actually an enum with very few values.

If you happen to use an bigger enum (with 5+ different values) or other types, the template version will be way worse than the parameter version.

In general, you will have no use doing what we saw in this article, but in the very specific case you have an enum that describes a “mode of use” of your function and has 2 or 3 possible values, take time to consider using it as template.

Keep in mind that this model, if seducing, is very specific and will not apply in your day-to-day coding.

## Semantic

What we achieved here could be seen as an overload of the `increase_and_square()` function. Indeed, we did several implementations of the same function (well, the template did it for us) that has a similar-yet-different behavior. This is exactly what overloading is about.

This is also why I described the enum as a “mode” : it describes how the function must work, and is more that than a real parameter.

Thanks for your attention and see you next week!

Author: Chloé Lourseyre

Author: Chloé Lourseyre

I often happen to see, on pretty old projects, the operators `&=` and `|=` used to update a boolean indicating success that is returned along successive function calls. As in the following example :

```bool success = true;
success &= DoOneThing();
success &= DoOneOtherThing();
success &= DoALastThing();
if (success)
std::cout << "Success !" << std::endl;
```

This way of writting is more concise than the usual :

```bool success = true;
success = success && DoOneThing();
success = success && DoOneOtherThing();
success = success && DoALastThing();
if (success)
std::cout << "Success !" << std::endl;
```

But you should be cautious, because behind the operators `&=` and `|=` hide a few subtelties that one should be aware of.

## Definition of the operators &= and |=

First, let’s see precise definition of `&=` and `|=`. In this section, I’ll only use `&=` as an example, but the behavious of `|=` is pretty much the same.

`&=` is an arithmetic binary operator, which permforms a binary AND and its assignation. In other terms, writting this :

```v1 &= v2;
```

is equivalent to this :

```v1 = v1 & v2;
```

except that v1 is only evaluated once.

For more insight about this, read the C++11 standard section `5.17 Assignment and compound assignment operators` or go to https://en.cppreference.com/w/cpp/language/operator_arithmetic

What we call “arithmetic binary operators” (which use the symbols `&`, `|`, `^`, `<<` and `>>`) are operators that perform bit-to-bit operations.

For instance :

```int a = 0b110;
int b = 0b011;
int c = a & b; // AND - 010
int d = a | b; // OR  - 111
int e = a ^ b; // XOR - 101
```

Writting a &= b; is thus performing a bit-to-bit AND operation on a and b, and assigns the result to a.

## Differences between &= and &&, |= and ||

The operators `&&` and `||` are, as for them, logical operators, as opposed to `&=` and `|=` who are arithmetic operators.

The use of `&=` and `|=` in a logical context is prone to diverge from what we could expect them to do.

Here are two example to illustrate that.

### Example 1

```#include <iostream>

bool foo()
{
std::cout << "call foo()" << std::endl;
return true;
}

int main() {
bool c = true;
std::cout << "Using |=" << std::endl;
c |= foo();
std::cout << "Using = and ||" << std::endl;
c = c || foo();
std::cout << "End" << std::endl;
return 0;
}
```

The function `foo()` always returns `true`, as long as writing on the standard output to indicate it’s been called.

In the `main()` function, we create a bool `c`, initialized true, on which we will perform the arithmetic binary operator `|=` and the logical operator `||`.

Here is the standard output :

``````Using |=
call foo()
Using = and ||
End``````

We can plainly see that in the |= case, foo() is called whereas it is not in the || case.

This is simply due to the fact that, in C++, logical operators are lazy. This means that if the right-hand-side of the operation can not change its result after evaluating the left-hand-side, then it won’t be evaluated.

Here, because `c` is already `true` in the expression `c || foo()`, no matter the value of `foo()` the result of the operation will always be `true`.

In the case of `|=`, it is a bit different. `|=` is not a logical operator, it does not reason in terms of `true` or `false`, but it performs arithmetic operations on integers. Thus, it needs to evaluate each side of the operation before evaluating the result. With arithmetic operations, both side are always evaluated.

Whether you wish the right-hand-side to be evaluated depends on the context. However, keep in mind that when C++ developpers see logical-like operations, they expect it to be lazy.

### Example 2

The following example, though quite uncommon in practice, can lead to errors that are difficult to investigate.

```#include <iostream>

int main() {
int c1 = true;
int c2 = 0b10;

if (c1)
std::cout << "c1 is true" <<std::endl;
else
std::cout << "c1 is false" <<std::endl;

if (c2)
std::cout << "c2 is true" <<std::endl;
else
std::cout << "c2 is false" <<std::endl;

if (c1&&c2)
std::cout << "c1&&c2 is true" <<std::endl;
else
std::cout << "c1&&c2 is false" <<std::endl;

c1 &= c2;

if (c1)
std::cout << "c1&=c2 -> c1 is true" <<std::endl;
else
std::cout << "c1&=c2 -> c1 is false" <<std::endl;

return 0;
}
```

Here, two variables are created : `c1` which is initialized to `true`, and `c2`, which is initialized to `0b10`.

Following four blocs performing logical evaluations :

• First we logically evaluate `c1`.
• Then, we similarly evaluate `c2`.
• Then we evaluate the logical operation `c1 && c2`.
• Finaly, we realise the arithmetic binary operation `c1 &= c2` just before evaluating `c1` again.

Here is the standard output of this code :

``````c1 is true
c2 is true
c1&&c2 is true
c1&=c2 -> c1 is false``````

Let’s see in details how this works :

First of all, `c1` is considered `true`. This is expected because it is explicitly initiliazed with `true`.

Secondly, `c2` is also considered `true`. This is so because, in C++, any non-null integer evaluates to `true`.

Thirdly, `c1 && c2` is evaluated to `true`. Indeed, because `c1` and `c2` and individually `true`, performing the AND operation on them is logically `true`.

Fourthly, we perform `c1 &= c2;`. By doing so, we actually perform `c1 & c2` and affect the result to `c1`.

However, according to the standard, `true` is equal to `1` when promoted to integer. Thus, `c1 & c2` is equivalent to `0b01 & 0b10`. The result to this operation really is `0b00`, the bit-to-bit AND operation is false for every bit.

The `0` value being evaluated to false in a logical expression, `c1` is, after all, `false`.

You won’t see this happen very often in live code, but there is plenty of situations, especially in legacy code, when an integer value that is not `1` is returned as if it was a true boolean.

## Conclusion

The use of &= and |= will do what we expect in 99% of the case. But in the remaining 1%, you’ll have major bugs difficult to investigate.

Moreover, I’d like to pinpoint a semantic problem here. The fact that we ue an arithmetic operation instead of a logical one mislead the reader and forces them to do an additional effort to pull this straight. In addition to that, it may prevent the compiler to perform optimization.

Writting `a = a && b;` instead of `a &= b;` is not much an effort, with only a few additional characters, but it will protect you from bugs and hold better semantics.

Thank you for your attention and meeting you next week !

NB : The example were done with clang and the compiler options `--std=c++20 -O3`

Author: Chloé Lourseyre