Использование переменных const, которые назначаются в ограниченной области в C

#c #reference #scope

#c #ссылка #область

Вопрос:

У меня возник конфликт между двумя лучшими практиками, и мне было интересно, есть ли способ получить лучшее из обоих миров.

Мне нужно получить вывод из выбора систем координат, и я хотел бы сделать следующее:

 // PSEUDO-CODE

const my_classamp; loads_global();
const my_classamp; loads_local();

GetLoads(COORDINATES coordinates)
{
    switch (coordinates)
    {
    case LOCAL:
        const my_classamp; loads = loads_local();
        break;
    case GLOBAL:
        const my_classamp; loads = loads_global();
        break;
    // etc.
    }
    loads.write();
}
  

Использование ссылок const полезно для производительности (и этот код часто вызывается), но если он const, его нельзя установить в пределах разделителя области видимости, такого как оператор switch или оператор if (или, действительно, оператор try, который я хотел сделать раньше).

Я мог бы поместить оператор loads.write(); в коммутатор, но на практике это не просто одна строка, и я ненавижу повторять код. Я мог бы также использовать указатели вместо ссылок (парадигма «const my_class * const my_object»), но это делает код более запутанным, чем использование ссылок.

Есть ли способ использовать ссылку const в окружающем коде или присвоить переменной const, которую я затем не буду / не могу изменить?

Ответ №1:

Если у вас C 11, вы можете использовать лямбда-выражение, чтобы скрыть инициализацию:

 GetLoads(COORDINATES coordinates)
{
    const my_classamp; loads = [amp;]() -> const my_classamp; {
      switch (coordinates)
      {
      case LOCAL:
          return loads_local();
          break;
      case GLOBAL:
          return loads_global();
          break;
      default:
          throw something;
      }
    }();  // Note the call operator here!
    loads.write();
}
  

Комментарии:

1. Теперь у нас есть лямбда-операторы ?!? Для разработчика LISP, а затем Python, это отличная новость!

2. @MikeSadler они у нас уже некоторое время (4 года) 🙂

3. Я не уверен, как спросить об этом деликатно, но не станет ли пуританин немного придираться к этому? Я пропустил введение макросов, и я не уверен, являются ли они полностью кошерным мейнстримом, или они рассматриваются как своего рода обходной путь…

4. @MikeSadler Какое это имеет отношение к макросам? В любом случае, я сам довольно сильно придерживаюсь принципа «предпочитаю чистоту кода» и нахожу это совершенно нормальным. Если вы имели в виду лямбды вместо макросов, то они, безусловно, часто используются (и поддерживаются многими ведущими специалистами C ).

Ответ №2:

У вас может быть третья функция, которая возвращает const my_classamp; и выполняет переключение:

 const my_classamp; loads_global();
const my_classamp; loads_local();

const my_classamp; GetLoads(COORDINATES coordinates)
{
    switch (coordinates)
    {
    case LOCAL:
        return loads_local();
    case GLOBAL:
        return loads_global();
    }
}

void DoSomething(COORDINATES coordinates)
{
    const my_classamp; variable = GetLoads(coordinates);
    variable.write();
}
  

Комментарии:

1. Я тоже собирался предложить это. Но что-то должно быть сделано для случая по умолчанию (не ЛОКАЛЬНОГО или ГЛОБАЛЬНОГО).)

2. Это определенно было бы стандартным способом решения проблемы — разделить код на части. Мне было интересно, есть ли способ сделать это «в строке» — особенно в случае, когда есть оператор ‘try’, в котором я чаще всего сталкивался с этой головоломкой.

Ответ №3:

Как насчет этого

 const my_classamp; loads = (coordinates == LOCAL) ? loads_local() : loads_global();
  

непосредственно перед switch блоком?

Комментарии:

1. К сожалению, мой псевдокод скрыл тот факт, что существует более двух вариантов…

2. Тогда я должен сказать, что Angew, возможно, правильный путь.

Ответ №4:

Для приведенного кода, почему бы не следующее:

 GetLoads(COORDINATES coordinates)
{
    switch (coordinates)
    {
    case LOCAL:
        loads_local().write();
        break;
    case GLOBAL:
        loads_global().write();
        break;
    }
}
  

Не самый модный, но он полностью устраняет проблему локальных переменных. Хорошо, у вас все еще есть временные, но этого нельзя избежать.

Комментарии:

1. Это определенно сработало бы в показанном случае, но я искал более общее решение, где использование переменной может быть слишком длинным для помещения в оператор switch.