Как избежать повторного объявления переменных с макросами C ++ - PullRequest
0 голосов
/ 18 апреля 2019

Я хочу написать простую функцию Macro.Поскольку этот макрос во многих местах используется разными обычными функциями c ++, я столкнулся с проблемой переменной области видимости.Я хотел бы знать, есть ли быстрый способ решить это?Большое спасибо.

Как видно из прилагаемого кода, в зависимости от того, был ли макрос вызван в функции в первый раз или нет, я хочу объявить или повторно использовать переменную ptrCandidate.Обратите внимание, что область видимости переменной находится в функции, а не в файле или модуле перевода.Другими словами, каждый раз, когда макрос вызывается в новой функции в первый раз, я хочу верхний макрос.И в той же функции, если макрос вызывается снова, я хочу нижний макрос.

#define EXPECT_MY_CLASS_EQ(expectedStr, candidateStr)       \
    auto ptrCandidate = parseAndGetPtr(candidateStr);       \
    doWork(ptrCandidate);                                   \
    EXPECT_EQ(expectedStr, convertToString(ptrCandidate));

#define EXPECT_MY_CLASS_EQ(expectedStr, candidateStr)       \
    ptrCandidate = parseAndGetPtr(candidateStr);            \
    doWork(ptrCandidate);                                   \
    EXPECT_EQ(expectedStr, convertToString(ptrCandidate));
void foo(){
    EXPECT_MY_CLASS_EQ("123","abcd")
}
void bar(){
    EXPECT_MY_CLASS_EQ("111","aabb")
    EXPECT_MY_CLASS_EQ("222","ccdd")
}
void foo(){
    auto ptrCandidate = parseAndGetPtr("abcd");
    doWork(ptrCandidate);
    EXPECT_EQ("123", convertToString(ptrCandidate));
}
void bar(){
    auto ptrCandidate = parseAndGetPtr("aabb");
    doWork(ptrCandidate);
    EXPECT_EQ("111", convertToString(ptrCandidate));

    /* auto */ ptrCandidate = parseAndGetPtr("ccdd");
    doWork(ptrCandidate);
    EXPECT_EQ("222", convertToString(ptrCandidate));
}

Ответы [ 3 ]

4 голосов
/ 18 апреля 2019

Как показано в другом ответе, в этом случае вам не нужен макрос.

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

Обратите внимание, что каждый из этих подходов фактически создает переменную new каждый раз, поэтому семантически отличается от вашего подхода с двумя отдельными макросами!Это особенно важно, если тип (назначенной) переменной имеет оператор присваивания не по умолчанию!

Если по какой-то причине вы полагаетесь на повторное использование одной переменной и ее присвоение, то IMOСамый простой подход - определить два макроса.Один макрос, который объявляет переменную (и инициализирует ее, если необходимо), а другой макрос с кодом, который использует переменную.

2 голосов
/ 18 апреля 2019

Вроде работает штатная функция:

void EXPECT_MY_CLASS_EQ(const char* expectedStr, const char* candidateStr)
{
    auto ptrCandidate = parseAndGetPtr(candidateStr);
    doWork(ptrCandidate);
    EXPECT_EQ(expectedStr, convertToString(ptrCandidate));
}
0 голосов
/ 18 апреля 2019

Возможным способом может быть использование __LINE__ или __COUNTER__ с символом препроцессора конкатенация .

В вашем случае вам, вероятно, не нужен макрос: предпочитайте некоторые static inline function.

Вот реальный пример (с использованием конкатенации и __LINE__) из файла моего Bismon проекта cmacros.h line 285 (это в C, но тот же трюк мог бы быть сделан в C ++)

#define LOCAL_FAILURE_HANDLE_ATBIS_BM(Fil,Lin,Lockset,Flabel,FcodVar,ReasonVar,PlaceVar) \
  struct failurehandler_stBM fh_##Lin                   \
   = {                                  \
     .pA = {.htyp = typayl_FailureHandler_BM},              \
     .failh_magic = FAILUREHANDLEMAGIC_BM,              \
     .failh_lockset = Lockset,                      \
     .failh_reason = NULL,                      \
     .failh_jmpbuf = {}};                       \
  curfailurehandle_BM = &fh_##Lin;                  \
  volatile int failcod_##Lin =  setjmp(fh_##Lin.failh_jmpbuf);      \
  FcodVar = failcod_##Lin;                      \
  if (failcod_##Lin) {                          \
    ReasonVar = fh_##Lin.failh_reason;                  \
    PlaceVar = fh_##Lin.failh_place;                    \
    goto Flabel;                            \
  };                                    \
  (void)0

#define LOCAL_FAILURE_HANDLE_AT_BM(Fil,Lin,Lockset,Flabel,FcodVar,ReasonVar,PlaceVar) \
  LOCAL_FAILURE_HANDLE_ATBIS_BM(Fil,Lin,Lockset,Flabel,FcodVar,ReasonVar,PlaceVar)

/// code using LOCAL_FAILURE_HANDLE_BM should probably backup and
/// restore the curfailurehandle_BM
#define LOCAL_FAILURE_HANDLE_BM(Lockset,Flabel,FcodVar,ReasonVar,PlaceVar)  \
LOCAL_FAILURE_HANDLE_AT_BM(__FILE__,__LINE__,Lockset,Flabel,FcodVar,ReasonVar,PlaceVar)

Возвращаясь к вашему вопросу, если вы все еще хотите макрос: просто создайте блок, например

#define EXPECT_MY_CLASS_EQ(expectedStr, candidateStr)   do{    \
    auto ptrCandidate = parseAndGetPtr(candidateStr);       \
    doWork(ptrCandidate);                                   \
    EXPECT_EQ(expectedStr, convertToString(ptrCandidate));} while(0)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...