Выборочная компиляция в коде вне макроса - PullRequest
2 голосов
/ 05 июня 2011

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

#if 0
static const char[] hello_world = "hello, world";
#endif

Можно ли в любом случае сделать то же самое с шаблонами?

На всякий случайЯ задаю не тот вопрос, вот что я пытаюсь сделать.Я хочу загрузить код при запуске приложения.Обычно я бы просто использовал конструктор, чтобы сделать все, что я хотел, и создать статическую переменную.Но я хочу, чтобы это происходило только в отладочной сборке и чтобы код не запускался во время сборки выпуска.Код, с которым я делаю это, создается с помощью макроса, поэтому я, кажется, не могу поместить «#if 0» внутри макроса и правильно его развернуть.

Есть ли в любом случаесделать это в C ++?

РЕДАКТИРОВАТЬ: Вот пример кода макроса, который я сейчас использую.

#define unittest(NAME)                                                  \
    struct unittest_ ## NAME :                                          \
        public unittest::unittest_template<unittest_ ## NAME>           \
    {                                                                   \
        unittest_ ## NAME() :                                           \
            unittest::unittest_template<unittest_ ## NAME>(#NAME) {}     \
        void run_test();                                                \
    };                                                                  \
    static unittest_ ## NAME NAME ## _unittest;                         \
    void unittest_ ## NAME::run_test()

Код используется путем:

unittest(addTest)
{
    assert_(5, 5); // there's an assert statement in the code
}

Мне нравится синтаксис того, как это выглядит, но я не вижу способа избавиться от тела функции с помощью макросов.Вместо этого я попытался использовать макрос начала / конца и получил:

#ifdef UNITTEST
#  define unittest_begin(NAME) // previous code
#  define unittest_end() // nothing needed
#else
#  define unittest_begin(NAME) #if 0
#  define unittest_end() #endif
#endif

Это не похоже на работу.

РЕДАКТИРОВАТЬ 2: Оригинальный вопрос сильно отличается от того, во что он превратился.Надеюсь, что имя поменяется, оно больше соответствует актуальному вопросу.

Ответы [ 4 ]

3 голосов
/ 05 июня 2011

Вам нужны условные выражения препроцессора, чтобы избавиться от объявлений. Но если вы просто хотите включить / отключить блок в середине функции, это не проблема. Вы можете использовать специализацию шаблонов, но самое простое - просто использовать if (_DEBUG) { ... }, при сборке релиза компилятор оптимизирует мертвый код.

1 голос
/ 05 июня 2011

Традиционно «отладочный» код будет заключен в блок, подобный этому, с использованием препроцессора, а не компилятора:

#ifdef DEBUG
// Some debugging code here...
#endif

... и передача -DDEBUG в препроцессор только для «отладки»"builds.

Однако было бы лучше рассмотреть различия между сборками" debug "и" release ".Блоки отладки обычно являются индикатором нерешенных проблем.

Я рекомендую полностью удалить эти условия.

0 голосов
/ 06 июня 2011

Учитывая ваше редактирование, кажется, что вы делаете это намного сложнее, чем должно быть. Там, где вы определяете свой макрос, укажите там блок #ifdef и выберите способ его определения.

#ifdef NDEBUG
#define unittest(NAME) static void dummy_func_##NAME()
#else
#define unittest(NAME)                                                  \
  struct unittest_ ## NAME :                                          \
      public unittest::unittest_template<unittest_ ## NAME>           \
  {                                                                   \          unittest_ ## NAME() :                                           \
          unittest::unittest_template<unittest_ ## NAME>(#NAME) {}     \
      void run_test();                                                \
  };                                                                  \
  static unittest_ ## NAME NAME ## _unittest;                         \
  void unittest_ ## NAME::run_test()  
#endif

Вы также можете использовать там одно определение и изменить main на

int main() {
    #ifndef NDEBUG
    unit_tests::run_all_tests(); //or whatever
    #endif
    //regular old code
}

Последний вариант - выборочная декларация самого статического параметра с использованием промежуточного макроса [не уверен на 100% в синтаксисе этого]

#ifndef NDEBUG
#define DECLARE(NAME) static unittest_##NAME NAME##_unittest;
#else
#define DECLARE(NAME) /* noop */
#endif

#define unittest(NAME) \
struct unittest_##NAME { /*add internals*/ }; \
DECLARE(NAME); \
void unittest_##NAME::run_test()

Во всех случаях тело функции все еще будет там, но поскольку вы никогда не вызываете его, это не имеет значения.

0 голосов
/ 05 июня 2011

Вы можете использовать что-то вроде условной метафункции из Boost.

boost::mpl::if_c <debug, MyDebuggingClass, EmptyClass>::type MyObject;

Выбирает тип переменной MyObject на основе значения выражения-константы debug.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...