Перечисление классов не было объявлено в этой области

Я программирую Arduino. В том же файле .ino, что и setup() и loop (), я определил следующее:

void setup()
{
  // код настройки
}

enum class CYCLE { TypeA, TypeB };

String cycleToString (CYCLE cycle) {
  if (cycle == CYCLE::TypeA) {
    return "TypeA";
  }
  else if (cycle == CYCLE::TypeB) {
    return "TypeB";
  }
  return "Undefined";
}

void loop()
{
  // код цикла
}

Но при компиляции он выдает ошибку:

sketch_v1:37:22: error: 'CYCLE' was not declared in this scope
 String cycleToString (CYCLE cycle) {
                      ^
/Users/.../sketch_v1.ino: In function 'String cycleToString(CYCLE)':
sketch_v1:37:31: error: 'String cycleToString(CYCLE)' redeclared as different kind of symbol
 String cycleToString (CYCLE cycle) {
                                  ^
/Users/.../sketch_v1.ino:37:8: note: previous declaration 'String cycleToString'
 String cycleToString (CYCLE cycle) {
        ^

Обратите внимание, что класс enum отлично работает и работает так, как задумано, но если я попытаюсь добавить функцию, полагаясь на тип ЦИКЛА, это приведет к ошибкам.

, 👍4

Обсуждение

Arduino builder имеет проблемы, если структуры, перечисления, классы не определены до первой функции, @Juraj

почему вы пишете "enum class` вместо просто "enum"?, @chrisl

@chrisl, enum class или enum struct из C++11-это перечисление, где значения могут использоваться только с именем типа перечисления типа CYCLE::TypeB., @Juraj

Не могли бы вы привести пример, который воспроизводит эту ошибку comiler? Я встроил ваш код в шаблон ' setup()-loop ()`, и он работает!, @Sim Son

Сделано @SimSon, и именно там скрывался "жучок". См.Ответ Юрая., @AJP


4 ответа


Лучший ответ:

13

Это известная ошибка Arduino builder, если у вас есть функции перед структурами, классами или перечислениями в sketch.

Скетч:

void foo() {
}

enum class CYCLE { TypeA, TypeB };

String cycleToString (CYCLE cycle) {
  if (cycle == CYCLE::TypeA) {
    return "TypeA";
  }
  else if (cycle == CYCLE::TypeB) {
    return "TypeB";
  }
  return "Undefined";
}

void setup() {
}

void loop() {
}

обрабатывается в этот файл .cpp

#include <Arduino.h>
#line 1 "/tmp/arduino_modified_sketch_327776/sketch_jun23a.ino"
#line 1 "/tmp/arduino_modified_sketch_327776/sketch_jun23a.ino"

#line 2 "/tmp/arduino_modified_sketch_327776/sketch_jun23a.ino"
void foo();
#line 7 "/tmp/arduino_modified_sketch_327776/sketch_jun23a.ino"
String cycleToString(CYCLE cycle);
#line 17 "/tmp/arduino_modified_sketch_327776/sketch_jun23a.ino"
void setup();
#line 22 "/tmp/arduino_modified_sketch_327776/sketch_jun23a.ino"
void loop();
#line 2 "/tmp/arduino_modified_sketch_327776/sketch_jun23a.ino"
void foo() {
}

enum class CYCLE { TypeA, TypeB };

String cycleToString (CYCLE cycle) {
  if (cycle == CYCLE::TypeA) {
    return "TypeA";
  }
  else if (cycle == CYCLE::TypeB) {
    return "TypeB";
  }
  return "Undefined";
}

void setup() {
}

void loop() {
}

как вы можете видеть, прямые объявления функций находятся перед первой функцией, поэтому перед перечислением.

Обходной путь для этой ошибки состоит в том, чтобы следовать хорошей практике и объявить все структуры, перечисления и классы перед первым определением функции.

,

пожалуйста, посмотрите мой ответ. Если вы можете отредактировать свой, чтобы включить / уточнить это, я удалю свой и отмечу ваш как правильный. Большое спасибо., @AJP

@AJP, я знаю об этой ошибке, поэтому я определил ее в вашем вопросе, но я не мог знать, какая функция у вас есть до перечисления. Я написал ответ более общий. Теперь я добавил кое-что о обходном пути., @Juraj

Выполнено. Спасибо @Juraj, @AJP

+1 за ответ и -1 за Arduino IDE. Действительный C++ должен просто компилироваться. Я не хочу изучать особенности другого языка программирования, если я уже умею программировать на C++. Я не могу поверить, что это не было решено за последние 4 года., @Thomas Weller

Я не понимаю обходной путь. У меня уже есть перечисление, объявленное перед функцией, использующей его в качестве аргумента, но я все равно получаю ошибку., @AgainPsychoX

@AgainPsychoX, ты должен ставить его перед всеми функциями, @Juraj


1

Обратите внимание, что это не ответ, так как ваш код идеально компилируется. (добавление функции настройки/цикла по умолчанию/пустой настройки / цикла).

Тем не менее, я хочу привести некоторые улучшения, которые не могут вписаться в комментарий:

  1. (необязательно) Выровняйте { и } друг под другом. Некоторые ставят { за черту, некоторые на новую черту; в основном это предпочтение. Но выравнивание { и } в основном более четкое.
  2. Поместите каждое значение типа/перечисления в новую строку; это облегчает добавление комментариев выше/после нее.
  3. За исключением тривиальных случаев, никогда не возвращайтесь из заявления, кроме последнего. В вашем случае функция довольно проста, но все же лучше сохранять возврат только в конце функции.
  4. Используйте инструкцию switch вместо нескольких инструкций if.

Таким образом, вы получаете:

enum class CYCLE 
{
  TypeA, 
  TypeB 
};

String cycleToString (CYCLE cycle) 
{
  String str;

  switch (cycle)
  {
  case CYCLE::TypeA:
    str = "TypeA";
    break;

  case CYCLE::TypeB:
    str = "TypeB";
    break;

  default:
    str = "Undefined";
    break;
  }

  return str;
}
,

Спасибо, Мишель. Полностью согласен с несколькими строками в перечислении. Я сократил его, чтобы помочь сократить вопрос. Мне нравится идея расположить " {"и"} " по вертикали. Сейчас я внес это изменение, и это хорошо, спасибо. Я не согласен с утверждением о переключении, так как мне не нравится ошибка с ошибкой, если вы забудете перерыв. Предупреждают ли вас распространенные C++ IDE? В качестве преимущества "переключения": предупреждает ли C++ об ошибке/, если вы не обрабатываете все типы перечислений? Возвращайтесь только один раз: да, полностью согласен. Спасибо., @AJP

Пожалуйста. Оператор if может быть столь же опасным (использование = вместо ==). Я не думаю, что вы получите предупреждение, забыв о перерыве (вы можете легко попробовать). C++ не предупреждает вас о том, что вы не проверяете все значения перечисления, но именно для этого используется ключевое слово "по умолчанию"., @Michel Keijzers

Верно. Я понимаю. По вашему опыту, является ли "если (a = x)` более распространенной ошибкой, чем забывание "перерыва"? Я предполагаю, что в конечном итоге все сводится к практике (?), Но я делал первое, возможно, 2 раза в своей жизни, но позже намного чаще, поэтому я лично избегаю "переключения" по этой причине., @AJP

Возможно, вам захочется прочитать: https://stackoverflow.com/questions/97987/advantage-of-switch-over-if-else-statement (на самом деле мне тоже было любопытно). В любом случае, переключатель более удобочитаем. Во всех (профессиональных) программных проектах, которые я выполнял, проверка кода не передавала бы кучу операторов if над переключателем (при сравнении с одной переменной). Кстати, я проверил, Arduino IDE не показывает никаких предупреждений (даже со всеми включенными предупреждениями)., @Michel Keijzers

Даже Visual Studio 2019 с включенными предупреждениями не отображается. Я работал с lint (статическая проверка C/C++), и я совершенно уверен, что в приложении упоминается забытый перерыв. Хотя в C разрешено иметь несколько операторов case (для выполнения одного и того же действия для нескольких значений). В основном люди ставят // Проваливаются за это, чтобы показать, что разрыв намеренно забыт., @Michel Keijzers


-1

Это работает, если вы переместите класс перечисления наверх, т. е.:

enum class CYCLE { TypeA, TypeB };

void setup()
{
  // setup code
}

String cycleToString (CYCLE cycle) {
  if (cycle == CYCLE::TypeA) {
    return "TypeA";
  }
  else if (cycle == CYCLE::TypeB) {
    return "TypeB";
  }
  return "Undefined";
}

void loop()
{
  // loop code
}
,

-1

Я нашел обходной путь на форумах Arduino: Разместите перечисления отдельно файл (я использую enums.hpp) и включаю его из основного файла эскиза (.ino), например #include "enums.hpp" ;.

,

включен ли у вас файл .hpp в то же место в ino, где изначально было перечисление?, @Juraj