Можно ли избавиться от вложенного switch в C++
Допустим, на вход приходит структура struct с 3мя полями a, b, c. Есть switch :
switch(struct.type)
case a:
switch(a.type)
case type1:
{
}
case type2:
{
}
case b:
switch(b.type)
case type3:
{
}
case type4:
{
}
case c:
switch(c.type)
case type5:
{
}
case type6:
{
}
Соответственно, type у каждого поля а, b и с может быть не по 2, а больше, да и самих полей может быть больше трех. Вопрос в том, можно ли в данном примере избавиться от вложенного switch и сделать код более читаемым и элегантным?
Ответы (2 шт):
В принципе нет. Единственное, возможно проще написать два линейных switch - один по struct.type, второй по struct.type.type. Т.к. struct.type - это один тип данных, а не разные объекты. Но это зависит от задачи (если действия по struct.type.type не зависят от действий по struct.type)
// выглядеть будет не так
switch(struct.type)
case a:
switch(a.type)
case b:
switch(b.type)
case c:
switch(c.type)
// а так
switch(struct.type)
case a:
switch(struct.type.type)
case type1:
case b:
switch(struct.type.type)
case type3:
case c:
switch(struct.type.type)
case type5:
// и возможно проще будет сделать 2 линейных последовательно
switch(struct.type)
case a:
case b:
case c:
switch(struct.type.type)
case type1:
case type2:
case type3:
В любом случае вопрос академический, без привязки к конкретной задаче точно сказать нельзя.
А если у вас разные типы, то тогда у вас struct.type - это std::variant или std::any. Но это уже область метапрограммирования.
Прежде всего следует помнить, что выражение в switch должно быть целочисленным, а в case константным (т.е. конкретная величина известна во время компиляции).
Поэтому, если у в вашей задаче значения struct.type и подтипов (a.type, b.type, ...) помещаются, скажем, в 16 бит, то можно написать следующий код:
uint32_t gen_type = (struct.type << 16);
switch (struct.type) {
case a: gen_type |= a.type; break;
case b: gen_type |= b.type; break;
...
}
#define GEN_TYPE(T1,T2) (((T1) << 16) | (T2))
switch (gen_type) {
case GEN_TYPE(a_type, type1) :
....
case GEN_TYPE(a_type, type2) :
....
case GEN_TYPE(b_type, type3) :
....
....
}
Вероятно, в реальной пограмме имеет смысл выделить код, формирующий переменную gen_type, в отдельную функцию. Тогда получим что-то вроде
switch ((gen_type = get_type(struct, a, b, c))) {
case GEN_TYPE(a_type, type1) :
....
case GEN_TYPE(a_type, type2) :
....
case GEN_TYPE(b_type, type3) :
....
....
}