C ++: Как создать enum внутри функции? - PullRequest
1 голос
/ 24 апреля 2011

Я хочу упростить вещи, не создавая список перечислений отдельно, но создавая перечисления вдоль вызова функции, которая создает данные, на которые я указываю с этими перечислениями.

Я пытался создать #define, который создал бы другой #define, но это не сработало:

int defcounter = 0;

#define make_def(enumname, somedata) \
    #define enumname defcounter \
    defcounter++; \
    func_call(somedata); \

void createstuff(){
    make_def(MY_ENUM_NAME, mydata);
    make_def(MY_OTHER_ENUMNAME, mydata);
}

void dostuff(){
    somefunc_call(MY_ENUM_NAME);
    somefunc_call(MY_OTHER_ENUMNAME);
}

Но это создаст ошибку на #define enumname:

error C2162: expected macro formal parameter

Как я могу сделать эту работу?

Ответы [ 4 ]

3 голосов
/ 24 апреля 2011

Невозможно создавать новые типы (классы, перечисления, объединения и т. Д.) Во время выполнения в C ++.Одной из основных особенностей C ++ является то, что он статически типизирован - все типы должны быть известны во время компиляции.

1 голос
/ 24 апреля 2011

Что именно вы хотите получить? Вам нужно объяснить, что, по вашему мнению, вы можете получить в качестве выходного сигнала препроцессора C.

У вас проблемы с областью действия и попытка определить макрос внутри текста замены другого макроса.

Область

Макрос make_def() вызывает неопределенную функцию 'func_call'. Функция createstuff() использует неопределенную переменную mydata. И функция dostuff(), кажется, вызывает неопределенную функцию somefunc_call() с перечислением, которое, возможно, могло бы быть определено внутри отдельной функции.

Если перечисление определено внутри одной функции, это перечисление недоступно для кода вне этой функции и, в частности, недоступно ни для вызываемых функций, ни для вызывающих функций. Это само по себе ограничивает полезность того, что вы пытаетесь сделать. (Да, значения перечисления могут быть неявно преобразованы в int или некоторый подобный тип, но в действительности это не тот тип перечисления, который используется.)

Определение макросов в макросах

Вы не можете создать макрос, который сам содержит #define или любую другую директиву препроцессора в тексте замены.

Если вызывается внешний макрос, расширение не интерпретирует внутреннее #define как директиву препроцессора, поэтому оно почти всегда заканчивается как ошибка. В контексте # должен быть оператором stringize, а слово 'define' после этого должно быть именем аргумента внешнего макроса, чтобы иметь возможность работать.

// Does not work as intended
#define macro(define, prefix) #define another(name)   foo(prefix ## name)
macro(something, other);

Формирует:

"something" another(name)  foo(othername);

_Pragma в C99 является частичным исключением из того, что «расширение макроса не может содержать директиву препроцессора», но оно (_Pragma) не начинается с #.

1 голос
/ 24 апреля 2011

Команды препроцессора (#define, #if, #pragma, #include, ...) не могут появляться в макросах / определениях. Проблема в том, что CPP (C-препроцессор) разделяет команды с помощью новых строк, в то время как C и C ++ не знают о новых строках. В C / C ++ вы можете написать все в одной строке, для команд препроцессора вы не можете.

#define MY_MACRO(name) \
    #define name##_macro something_cool \
    enum name{ \
      .... \
    }

// somewhere else
void myfunc(){
  MY_MACRO(myfunc_enum);
}

Теперь, во время предварительной обработки, все эти строки склеиваются в одну большую строку благодаря обратной косой черте \:

#define MY_MACRO(name) #define name##_macro something_cool enum name{....}

Теперь, как этот макрос будет выглядеть при использовании?

void myfunc(){
  #define name##_macro something_cool enum name{....};
}

Теперь препроцессор должен снова запустить этот #define. Но что именно принадлежит #define, а что нет? Для кодера было ясно, когда макрос был написан отдельными строками, но теперь его уже нет.

0 голосов
/ 24 апреля 2011

Ваш макрос неверен, поскольку вы не можете использовать макрос для создания другого макроса, к сожалению, так как toke # имеет особое значение в раскрывающемся списке: он может заключать в кавычки аргумент макроса или раскрывать другой макрос.Один простой (хотя и плохо спроектированный) способ сделать это - просто использовать старый стиль c #define MY_ENUM_NAME value, так как макрос c не учитывает область видимости, но это не будет хорошим дизайном.Другая возможность - передать строковые аргументы и хэшировать их, но все зависит от того, что вы хотите сделать.

...