我想用更优雅的东西代替大开关.
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;
}
...
}
}
正如您在示例类A和B中看到的那样,外部没有什么不同.
我想找到一种消除实例化正确类并在其上调用相同方法的开关的方法,在我的真实代码中,该开关的长度超过1000行,并且有更多的类,但是我找不到任何方法摆脱它.
在实际代码中,我有2个枚举而不是char,并且有更多的开关,但是我希望问题清楚.
我的想法之一是在基类上使用模板,但是我没有找到一种方法来在没有巨大切换的情况下实例化正确的孩子.
编辑
我收到了来自网络的数据包,并希望对其进行解析和处理.这些类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();
});
进一步考虑:
>如果它们都具有相同的多态接口,则可以决定仅使用此接口来创建对象.
>如果您的范围内有漏洞,则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>());
}