Reputation: 194
I'm trying to refactor some code. Basically is a state machine based with enum. There are a lot of switch statements and functions that got called with different names and ambiguations.
Since they force me to keep the enum, I would like to refactor it using template. Basically I would like to use template to implement polymorphism. Since the states are limited there should be a way but I cannot find the best one.
#include <iostream>
enum class AnimalType
{
Dog,
Cat
};
template<AnimalType T>
void Foo()
{
std::cout << "Unknown animal\n";
}
template<>
void Foo<AnimalType::Dog>()
{
std::cout << "I'm a dog\n";
}
template<>
void Foo<AnimalType::Cat>()
{
std::cout << "I'm a cat\n";
}
int main()
{
AnimalType CurrentAnimal = AnimalType::Dog;
// Foo<CurrentAnimal>(); Won't compile
return 0;
}
Upvotes: 0
Views: 92
Reputation: 2888
As mentioned by @P Kramer's answer:
Note : you can't use your construct to make decissions at runtime. Templates only lead to compile time polymorphism.
You can't do that, but you can use the Compile-Time Dispatch and runtime parameter by passing the desired value as parameter while they are separated by Function Template Specialization. For example turn your enumerations value into actual types:
struct animal_t
{
std::string const name;
explicit animal_t(std::string const& name_)
: name(name_)
{
}
auto operator()() const
{
return name;
}
};
struct dog_t final : animal_t
{
using animal_t::animal_t;
};
struct cat_t final : animal_t
{
using animal_t::animal_t;
};
They you are able to specialize the function template:
/*!
*
* Other Programmer(s) interface
*
*/
template<typename Animal>
auto function(Animal const&)
{
assert(false);
}
/*!
*
* Implementation
*
*/
template<>
auto function(cat_t const& animal)
{
return animal();
}
template<>
auto function(dog_t const& animal)
{
return animal();
}
Now user (other programmer) of your library could easily interact with it for example by a GUI library:
QObject::connect(button1, &QPushButton::clicked, &application, [] {
cat_t cat("Some Cat");
auto const message = QString::fromStdString(function(cat));
QMessageBox::information(nullptr, " ", message);
});
QObject::connect(button2, &QPushButton::clicked, &application, [] {
dog_t dog("Some Dog");
auto const message = QString::fromStdString(function(dog));
QMessageBox::information(nullptr, " ", message);
});
Result: just for copy/past: runtime_dispatch_v1
Upvotes: 0
Reputation: 12849
You need a compile time evaluatable constant, this will work
int main()
{
constexpr auto CurrentAnimal = AnimalType::Dog;
Foo<CurrentAnimal>();
return 0;
}
or directly use
Foo<AnimalType::Dog>();
Note : you can't use your construct to make decissions at runtime. Templates only lead to compile time polymorphism
Upvotes: 1