我有这个小问题,请看看:
#include <iostream>
enum class AnimalType
{
bird,
mammal,
lizard,
fish,
};
template<int LEGCOUNT, typename T>
class AbstractAnimal
{
public:
T printLegCount() { std::cout << LEGCOUNT << std::endl; return 0; }
};
// The second parameter is NOT the leg type, it is just
// a parameter to make each method signature unique
// as it is in my real source code
class Mammal : public AbstractAnimal<4, double>{};
class Bird : public AbstractAnimal<2, int>{};
class Lizard : public AbstractAnimal<4, float>{};
class Fish : public AbstractAnimal<0, long long>{};
void printLegCount(AnimalType animalType)
{
switch (animalType)
{
case AnimalType::bird: Bird{}.printLegCount(); break;
case AnimalType::mammal: Mammal{}.printLegCount(); break;
case AnimalType::lizard: Lizard{}.printLegCount(); break;
case AnimalType::fish: Fish{}.printLegCount(); break;
}
}
int main()
{
AnimalType type = AnimalType::bird;
printLegCount(type);
return 0;
}
实际上我的代码中的AnimalType枚举很大(40个或更多条目)。 printLegCount中的开关也很大。我有一些类似printLegCount的函数可以用switch case写入。
因此,每当我需要实例化某些类时,我最终会编写一个冗长而可怕的切换案例。我输入的所有内容都是运行时枚举值(在编译时无法解析)。一个枚举值对应一个类。起初我想写一个向量或数组,但我的类不共享任何共同的祖先。实际上我不想要一个共同的祖先,因为我不能有任何常用的方法,这就是printLegCount返回T的原因,以模仿我的生产代码。共同的祖先是一个空壳,我必须转发到真实类型才能使用它。
有没有办法写出类似的东西:
void printLegCount(AnimalType animalType)
{
no_idea_how_to_write_it(animalType).printLegCount(); // h4lp plx
}
而不是巨大的开关案例。
答案 0 :(得分:3)
你在谈论这样的事吗?
#include <iostream>
enum class AnimalType
{
bird,
mammal,
lizard,
fish,
};
template<AnimalType LEGCOUNT, typename T>
class AbstractAnimal
{
public:
T printLegCount() { std::cout << (int)LEGCOUNT << std::endl; return 0; }
protected:
};
class Mammal : public AbstractAnimal<AnimalType::mammal, double>{};
class Bird : public AbstractAnimal<AnimalType::bird, int>{};
class Lizard : public AbstractAnimal<AnimalType::lizard, float>{};
class Fish : public AbstractAnimal<AnimalType::fish, long long>{};
template<AnimalType A, class T> void printLegCount() {
AbstractAnimal<A, T>{}.printLegCount();
}
void foo() {
printLegCount<AnimalType::bird, int>();
}
答案 1 :(得分:3)
您可以创建一个调度员:
// Same order as enum AnimalType
using AnimalTuple = std::tuple<Bird, Mammal, Lizard, Fish>;
// Helper function as gcc has problem to expand variadic for the lambda
template <typename T, typename F>
std::function<void()> call_with_default(F&& f)
{
return [f]() {f(T{});};
}
template <typename F, std::size_t...Is>
void dispatch(AnimalType animalType, F&& f, std::index_sequence<Is...>)
{
std::function<void()> fs[] = {
call_with_default<std::tuple_element_t<Is, AnimalTuple>>(f)...
};
fs[static_cast<int>(animalType)]();
}
template <typename F>
void dispatch(AnimalType animalType, F f)
{
constexpr auto AnimalCount = std::tuple_size<AnimalTuple>::value
dispatch(animalType, f, std::make_index_sequence<AnimalCount>{});
}
然后叫它:
dispatch(animalType, [](auto t) { t.printLegCount(); });
如果您不能使用C ++ 14,则必须创建通用仿函数
struct LegCountPrinter {
template <typename T>
void operator(T t) const { t.printLegCount(); }
};
// later
dispatch(animalType, LegCountPrinter{});