我想用更优雅的东西替换大开关。
class Base
{
public:
Base(void*data, int size);
virtual void Something() = 0;
}
class A : public Base
{
public:
A(void*data, int size) : Base(data, size) {}
void Something() override;
}
class B : public Base
{
public:
B(void*data, int size) : Base(data, size) {}
void Something() override;
}
...
{
char c = input;
switch (c)
{
case 'a':
{
A obj(data, size);
obj.Something();
break;
}
case 'b':
{
B obj(data, size);
obj.Something();
break;
}
...
}
}
Run Code Online (Sandbox Code Playgroud)
如您在本例中类看A,并B没有来自外部的不同。我想找到一种方法来消除只实例化正确类并在其上调用相同方法的开关,在我的实际代码中,该开关长达 1000 多行,并且还有更多的类,但我找不到任何方法摆脱它。
在实际代码中,我有 2 个枚举而不是字符,并且有更多开关,但我希望问题很清楚。
我的一个想法是在基类上使用模板,但我没有找到如何在没有那个巨大开关的情况下实例化正确的孩子的方法。
编辑
我从网络收到数据包并想解析它并处理它。这些类a, b, ...没有任何私有或公共成员,基类只有指向日期的原始指针和指向响应套接字的共享指针(也来自构造函数)。
我希望编译器用模板为我生成那个开关?或其他一些机制来删除重复的源代码。现在它仍处于测试阶段,但它每秒处理大约 1000 个数据包,所以我不想在堆上的分配和解除分配上移除开关并失去性能。
找到 的实现static_for,它本身很简单:
using list = std::tuple<A, B, C, D, E, F, G, ...>;
const auto n = c - 'a';
static_for<std::tuple_size<list>()>([&](auto N){
if (n != N)
return;
using T = std::tuple_element_t<list, N>;
T obj(data, size);
obj.Something();
});
Run Code Online (Sandbox Code Playgroud)
进一步考虑:
如果它们都具有相同的多态接口,您可以决定仅使用它来创建对象。
如果你的范围有漏洞,if constexpr并且std::is_same是你的朋友。
使用一些专用的 typelist-type 可能比使用 更好std::tuple,但这在紧要关头有效。
一个未经修饰、快速且肮脏的示例实现static_for():
template <std::size_t Is, class F>
void static_for_impl(F&& f, std::index_sequence<Is...>) {
f(std::integral_constant<std::size_t, Is>()), ...;
}
template <std::size_t N, class F>
void static_for(F&& f) {
static_for_impl(f, std::make_index_sequence<N>());
}
Run Code Online (Sandbox Code Playgroud)