C ++如何替换构造函数开关? [英] C++ how to replace constructor switch?

查看:82
本文介绍了C ++如何替换构造函数开关?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用更优雅的东西代替大型交换机。

  class基础
{
public:
Base(void * data,int size);
virtual void Something()= 0;
}
A类:公共基本
{
公共:
A(无效*数据,整数大小):基本(数据,大小){}
void Something()覆盖;
}
B类:公共基本
{
公共:
B(无效*数据,整数大小):基本(数据,大小){}
void Something()覆盖;
}
...

{
char c =输入;
开关(c)
{
case'a':
{
一个obj(data,size);
obj.Something();
休息时间;
}
格‘b’:
{
B obj(data,size);
obj.Something();
休息时间;
}
...
}
}

在示例类 A B 中看到的与外面没有什么不同。
我想找到一种消除实例化正确类并对其调用相同方法的开关的方法,在我的真实代码中,该开关的长度超过1000行,并且有更多的类,但是我不能



在实际代码中,我有2个枚举而不是char,并且有更多的开关,但是我希望问题清楚。 p>

我的想法之一是在基类上使用模板,但是我没有找到一种方法来实例化正确的孩子,而无需进行巨大的切换。



编辑
我收到了来自网络的数据包,并希望对其进行解析和处理。这些类 a,b,... 没有任何私有或公共成员,基类仅具有指向日期的原始指针,以及指向响应套接字的共享指针(同样来自构造函数) )。



我希望编译器使用 templates 或其他某种机制为我生成该开关,以删除重复的源代码。现在它仍处于测试阶段,但是它每秒处理大约1000个数据包,因此我不想在堆的分配和释放上删除交换机并失去性能。

解决方案

找到 static_for 的实现,这很简单:

 使用列表= 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;
使用T = std :: tuple_element_t< list,N> ;;
T obj(data,size);
obj.Something();
});

其他注意事项:


  1. 如果它们都具有相同的多态接口,则可以决定仅使用它来创建对象。


  2. 如果有孔在您的范围内,如果constexpr std :: is_same 是您的朋友。


  3. 使用某些专用的typelist-type可能比 std :: tuple 更好,但这在一定程度上可行。


static_for()的未抛光,快速且肮脏的示例实现:

 模板< std :: size_t是,类F> 
void static_for_impl(F& f,std :: index_sequence< Is ...>)){
f(std :: integral_constant< std :: size_t,Is>()),... ;
}

模板< std :: size_t N,类F>
void static_for(F& f){
static_for_impl(f,std :: make_index_sequence< N>());
}


I would like to replace big switch with something more elegant.

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;
    }
    ...
  }
}

as you see in the example class A and B do not differ from outside. I would like to find a way to eliminate that switch that just instantiate correct class and call same method on it, in my real code that switch is over 1000 lines long, and there is much more classes, but I can not find any way to get rid of it.

In real code I have 2 enums instead of char, and there are more switches, but I hope problem is clear.

One of my ideas was use templates on base class, but I did not find a way how to instantiate correct child without that huge switch.

EDIT I receive packet from network and want to parse it and handle it. These classes a, b, ... do not have any private or public members, base class have only raw pointer to date, and shared pointer to response socket (also from constructor).

I would like the compiler to generate that switch for me with templates? or some other mechanic to remove that repetitive source code. Right now it is still in testing phase, but it handle around 1000 packets per second, so I do not want to remove switch and lose performance, on allocation and deallocation on the heap.

解决方案

Find an implementation of static_for, and it's simplicity itself:

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();
});

Further considerations:

  1. If they all have the same polymorphic interface, you could decide to only use this for creating the object.

  2. If you have holes in your range, if constexpr and std::is_same are your friends.

  3. It might be better to use some dedicated typelist-type rather than std::tuple, but this works in a pinch.

An unpolished, quick and dirty example-implementation for 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>());
}

这篇关于C ++如何替换构造函数开关?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆