Consider the example code below.
#include <iostream>
enum class FruitType {
APPLE,
ORANGE
};
class Fruit {
uint64_t apple_count;
uint64_t orange_count;
public:
Fruit() : apple_count(0), orange_count(0) {}
void increase_count(FruitType type) {
if (type == FruitType::APPLE)
apple_count++;
else
orange_count++;
}
void print() {
std::cout << "apple_count: " << apple_count << std::endl;
std::cout << "orange_count: " << orange_count << std::endl;
}
};
int main(int, char**) {
Fruit fruit;
fruit.increase_count(FruitType::APPLE);
fruit.increase_count(FruitType::ORANGE);
fruit.increase_count(FruitType::APPLE);
fruit.increase_count(FruitType::APPLE);
fruit.increase_count(FruitType::ORANGE);
fruit.print();
return 0;
}
I want the increase_count
function to effectively compile to increase_count_apple
and increase_count_orange
. This is a simplified example of another class where such compile-time optimisation helps me at runtime, in theory. Intuitively, this feels possible using templates, but I am unable to arrive at a satisfactory output.
By making increase_count
a template that takes a non-type template paramter you can do
class Fruit {
uint64_t apple_count;
uint64_t orange_count;
public:
Fruit() : apple_count(0), orange_count(0) {}
template <FruitType type>
void increase_count() {
if constexpr (type == FruitType::APPLE)
apple_count++;
else
orange_count++;
}
void print() {
std::cout << "apple_count: " << apple_count << std::endl;
std::cout << "orange_count: " << orange_count << std::endl;
}
};
int main(int, char**) {
Fruit fruit;
fruit.increase_count<FruitType::APPLE>();
fruit.increase_count<FruitType::ORANGE>();
fruit.increase_count<FruitType::APPLE>();
fruit.increase_count<FruitType::APPLE>();
fruit.increase_count<FruitType::ORANGE>();
fruit.print();
return 0;
}
which removes the branch at compile time and fruit.increase_count<FruitType::APPLE>
effectively calls increase_count_apple
and fruit.increase_count<FruitType::ORANGE>()
calls increase_count_orange
.