Вопрос шаблона языка C ++ - PullRequest
6 голосов
/ 08 января 2010

Ниже приведен небольшой тестовый пример, демонстрирующий проблему, которую я пытаюсь решить с помощью шаблонов в C ++:

template<typename T>
void
unused(T const &) {
  /* Do nothing. */
}

int main() {
  volatile bool x = false;
  unused(!x); // type of "!x" is bool
}

Как написано ниже, компилятор g ++ v3.4.6 жалуется:

test.cc: In constructor `test::test()':
test.cc:11: error: invalid initialization of reference of type 'const volatile bool&' from expression of type 'volatile bool'
test.cc:3: error: in passing argument 1 of `void unused(const T&) [with T = volatile bool]'

Целью здесь является неиспользованное подавление предупреждений о неиспользуемых переменных, которые появляются в оптимизированном коде. У меня есть макрос, который выполняет проверку утверждения, и в оптимизированном коде утверждение исчезает, но я хочу, чтобы любые переменные в выражении утверждения оставались ссылочными, чтобы не получать предупреждения о неиспользуемых переменных только в оптимизированном коде. В определении шаблонной функции unused () я использую ссылку, чтобы код конструктора копирования не запускался непреднамеренно, чтобы компилятор полностью исключил вызов неиспользованного кода.

Для заинтересованных лиц макрос утверждения выглядит следующим образом:

#ifdef NDEBUG
#  define Assert(expression) unused(expression)
#else // not NDEBUG
#  define Assert(expression)      \
{         \
  bool test = (expression);      \
     \
  if (!test) {        \
    if (StopHere(__LINE__, __FILE__, __PRETTY_FUNCTION__,  \
                    #expression, false)) {    \
      throw Exit(-1); /* So that destructors are run. */  \
    }         \
  }         \
}
#endif // else not NDEBUG

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

template<typename T>
void
unused(T const) {
  /* Do nothing. */
}

Однако тогда другие случаи, вызывающие unused (), завершаются неудачно из-за неоднозначности, когда на аргумент можно ссылаться с чем-то вроде:

file.h:176: error: call of overloaded `unused(bool)' is ambiguous
myAssert.h:27: note: candidates are: void unused(T) [with T = bool]
myAssert.h:34: note:                 void unused(const T&) [with T = bool]

Итак, мой вопрос: как я могу изменить неиспользованный () или перегрузить его, чтобы он соответствовал следующим требованиям:

  1. Вызов unused () может быть оптимизирован компилятором до запрета.
  2. Это приводит к тому, что любые переменные, присутствующие в выражении, передаваемом unused (), представляются использованными и, следовательно, не приводят к предупреждению об их определении, но не использовании.
  3. На аргумент unused () можно или нельзя ссылаться.
  4. Аргументом unused () может быть объект с дорогим конструктором копирования, который не должен вызываться при вызове unused ().

Спасибо.

-William

Ответы [ 10 ]

3 голосов
/ 08 января 2010

Обычный (и гораздо более простой) способ добиться этого - просто привести результат к void.

(void) x;

где x - это какое-либо иное значение без ссылки.

2 голосов
/ 08 января 2010

Чарльз Николсон предлагает сделать что-то подобное, чтобы пометить неиспользуемые переменные по причинам, объясненным в этой статье :

#define UNSUSED(a) ((void)sizeof(a))

Краткая версия ... sizeof не оценивает выражение, но компиляторы все еще считают его "использованным", когда оно рассматривается в этом контексте.

Я считаю, что это удовлетворяет всем 4 вашим критериям, в частности потому, что sizeof () может принимать любое допустимое выражение, и потому что выражение не будет оцениваться (и, следовательно, не будет генерировать какой-либо код).

1 голос
/ 09 января 2010

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

1 голос
/ 08 января 2010

Как сказал Йоханнес в комментариях, вы столкнулись с ошибкой компилятора.Вы можете обойти это, явно преобразовав в bool:

unused( bool( !readWriteActivated) ); // add bool() to any (!volatile_bool_var)

Старый ответ (но все же неплохая идея)

Если я вспоминаю постоянные изменяющиеся правила квалификациивсе, что вам нужно, это больше квалифицировать фиктивную переменную.По сути, вы просто хотите отправить сообщение об ошибке обратно в объявленный тип: vP.

template<typename T>
void
unused(T const volatile &) { // only change is to add "volatile"
  /* Do nothing. */
}

Кроме того, приятно, что вы ставите const после типа, к которому он принадлежит.

1 голос
/ 08 января 2010

Измените определение неиспользованного:

inline void unused(bool) {}

Поскольку вы уже хотите получить выражение, для которого требуется преобразование в bool, оно выполняет это преобразование и ничего больше. Inline позволяет оптимизировать компилятор, в том числе в ситуациях, когда выражение не имеет побочных эффектов (но вам придется проверить, чтобы точно знать, что происходит в сложных ситуациях).

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

1 голос
/ 08 января 2010

Лучшее решение, которое я видел, выглядит так:

#define UNUSED(x) ((void)x)

Это портативное устройство, которое успешно подавляет предупреждение.

EDIT

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

#if defined ASSERT_ENABLED
#define TEST(test) (!(test)) ? assert_failed(# test, __FILE__, __LINE__) : (void)0    
#else
#define TEST(ignore) ((void)0)
#endif

Это не даст никакого кода, если не определено ASSERT_ENABLED, и не выдаст предупреждение о неиспользуемых переменных. Примерно так работает макрос assert в libc.

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

0 голосов
/ 11 января 2010

Это ошибка:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42655

На неиспользованном уровне () нет работы. Вместо этого каждое вхождение можно обойти, введя временную переменную перед вызовом unused ():

template<typename T>
void
unused(T const &) {
  /* Do nothing. */
}

int main() {
  volatile bool x = false;
  bool avoidGCC42655 = !x; // type of "!x" is bool
  unused(avoidGCC42655);
}
0 голосов
/ 08 января 2010

Если вы хотите отключить предупреждение о неиспользуемой переменной, почему вы называете его
неиспользуемый (readWriteActivated!); ? Почему ты не можешь просто назвать это как
неиспользованные (readWriteActivated); и сделайте код как

template<typename T>
void UnUsed(const T& )
{

}

Дополнительные ссылки см. В блоге Херба Саттера Здесь

EDIT: удалено имя параметра в функции. Это работает для неиспользуемый (readWriteActivated!); а также.

0 голосов
/ 08 января 2010

Почему вы передаете !readWriteActivated вместо readWriteActivated, если значение выражения не имеет значения?

0 голосов
/ 08 января 2010

Почему бы не пропустить шаблоны вообще и не идти с эллипсами.

inline void unused (...) { /* do nothing */ }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...