如何使用枚举专门化一个函数
How to specialize a function using enum
我正在尝试重构一些代码。基本上是一个基于枚举的状态机。
有许多 switch 语句和函数以不同的名称和歧义被调用。
既然他们强迫我保留枚举,我想用模板重构它。基本上我想使用模板来实现多态性。由于州有限,应该有办法,但我找不到最好的。
#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;
}
您需要一个编译时可计算常量,这会起作用
int main()
{
constexpr auto CurrentAnimal = AnimalType::Dog;
Foo<CurrentAnimal>();
return 0;
}
或直接使用
Foo<AnimalType::Dog>();
注意:您不能使用您的构造在运行时做出决定。
模板只会导致编译时多态
如@P Kramer的回答所述:
Note : you can't use your construct to make decissions at runtime. Templates only lead to compile time polymorphism.
你不能那样做,但你可以通过将所需值作为参数传递来使用编译时调度和运行时参数,同时它们由函数模板专业化分隔。例如将您的枚举值转换为实际类型:
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;
};
您可以专门化函数模板:
/*!
*
* 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();
}
现在您的库的用户(其他程序员)可以轻松地与它交互,例如通过 GUI 库:
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);
});
结果: 仅用于 copy/past:runtime_dispatch_v1
我正在尝试重构一些代码。基本上是一个基于枚举的状态机。 有许多 switch 语句和函数以不同的名称和歧义被调用。
既然他们强迫我保留枚举,我想用模板重构它。基本上我想使用模板来实现多态性。由于州有限,应该有办法,但我找不到最好的。
#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;
}
您需要一个编译时可计算常量,这会起作用
int main()
{
constexpr auto CurrentAnimal = AnimalType::Dog;
Foo<CurrentAnimal>();
return 0;
}
或直接使用
Foo<AnimalType::Dog>();
注意:您不能使用您的构造在运行时做出决定。 模板只会导致编译时多态
如@P Kramer的回答所述:
Note : you can't use your construct to make decissions at runtime. Templates only lead to compile time polymorphism.
你不能那样做,但你可以通过将所需值作为参数传递来使用编译时调度和运行时参数,同时它们由函数模板专业化分隔。例如将您的枚举值转换为实际类型:
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;
};
您可以专门化函数模板:
/*!
*
* 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();
}
现在您的库的用户(其他程序员)可以轻松地与它交互,例如通过 GUI 库:
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);
});
结果: 仅用于 copy/past:runtime_dispatch_v1