Ниже небольшой тестовый сценарий, который демонстрирует проблему, что я пытаюсь решить шаблоны использования в 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]'
Цель здесь состоит в том, чтобы иметь неиспользованный, подавляют предупреждения неиспользуемой переменной, которые происходят в оптимизированном коде. У меня есть макрос, который делает проверку утверждения, и в оптимизированном коде уходит утверждение, но я хочу, чтобы любые переменные в выражении утверждения остались ссылаемыми так, чтобы я не получал предупреждения неиспользуемой переменной только в оптимизированном коде. В определении для неиспользованного () обрабатывают функцию по шаблону, я использую ссылку так, чтобы никакой код конструктора копии не был непреднамеренно выполнен так, чтобы вызов к неиспользованному мог полностью игнорироваться компилятором.
Для заинтересованных, макрос утверждения похож на это:
#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. */
}
Однако затем другие случаи, называющие неиспользованным (), перестали работать из-за неоднозначности, когда аргумент может быть сделан ссылка на с чем-то как:
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]
Таким образом, мой вопрос, как может я изменяться неиспользованный () или перегружать его так, чтобы это отвечало следующим требованиям:
Спасибо.
- William
Как сказал Йоханнес в комментариях, вы столкнулись с ошибкой компилятора. Вы можете обойти это, явно преобразовав в bool
:
unused( bool( !readWriteActivated) ); // add bool() to any (!volatile_bool_var)
Если я напомню правила квалификации const-volatile, все, что вам нужно, это квалифицировать фиктивная переменная подробнее. По сути, вы просто хотите повторить сообщение об ошибке в объявленном типе: vP.
template<typename T>
void
unused(T const volatile &) { // only change is to add "volatile"
/* Do nothing. */
}
Также приятно, что вы поместили const
после типа, которому он принадлежит.
Почему вы передаете ! ReadWriteActivated
вместо readWriteActivated
, если значение выражения не имеет значения?
Обычный (и гораздо более простой) способ добиться этого - просто привести результат к void
.
(void) x;
где x - какое-то другое значение, на которое нет ссылки.
Чарльз Николсон предлагает сделать что-то подобное для пометки неиспользуемых переменных по причинам, объясненным в этой статье :
#define UNSUSED(a) ((void)sizeof(a))
Короткая версия... sizeof не оценивает выражение, но компиляторы все равно считают его "использованным", когда его видят в этом контексте.
Я считаю, что это удовлетворяет всем 4 вашим критериям, а именно потому, что sizeof() может принять любое корректное выражение, и потому, что выражение не будет вычислено (и, следовательно, не сгенерирует никакого кода).
Измените определение unused:
inline void unused(bool) {}
Поскольку вам уже нужно выражение, для которого требуется преобразование в bool, оно выполняет это преобразование и ничего больше. Inline позволяет компилятору оптимизировать, в том числе в ситуациях, когда выражение не имеет побочных эффектов (но вам нужно будет выполнить тестирование, чтобы точно знать, что происходит в сложных ситуациях).
Кроме того, это устраняет общую проблему с большинством макросов assert: если выражение действительно имеет побочные эффекты, они всегда будут вычисляться. (В зависимости от использования это может быть очень хорошо или очень плохо.)
Почему бы вообще не пропустить шаблоны и не использовать многоточия.
inline void unused (...) { /* do nothing */ }
Если вы хотите подавить предупреждение о неиспользуемой переменной, почему вы называете ее
.
неиспользованный(!readWriteActivated); ? Почему ты не можешь просто назвать это
неиспользуемый(readWriteActivated);
и сделайте код как
template<typename T>
void UnUsed(const T& )
{
}
Для более подробных ссылок смотрите запись в блоге от Herb Sutter Here
EDIT: Удалено имя параметра в функции. Это работает для неиспользуемая(!readWriteActivated); а также.
Предупреждение компилятора не имеет никакого отношения к используемому или неиспользуемому. Передается переменная volatile - readWriteActivated - в функцию, которая не принимает volatile reference. Попробуйте const cast.
Лучшее решение, которое я видел, похоже на это:
#define UNUSED(x) ((void)x)
Это портативно, и подавляет предупреждение успешно.
Редактировать :
Так как вы заявили, что это больше похоже на утверждение, то вы, вероятно, должны сделать что-то вроде этого:
#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 работает.
Я полагаю, что проблема заключается в том, что переменные используются только в утверждении, который является плохим способом делать то, что вы хотите. Почему бы не отметить его как неиспользованным и использовать макрос утверждения в отдельности , таким образом, понятно, что переменная на самом деле не используется для ничего, но вы все равно получите свое утверждение от отладки. Просто решая проблемы индивидуально.
Это ошибка:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42655
На уровне unused () нет никакого решения. Вместо этого каждое вхождение можно обойти, введя временную переменную перед вызовом 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);
}