Ответ 1
Да, но вы, скорее всего, получите еще одно предупреждение.
Стандартный способ сделать это: (void)iid;
.
Очень технически это все равно может загружать iid
в регистр и ничего не делать. Конечно, это очень глупо на части компиляторов (я сомневаюсь, что кто-нибудь это сделает, если он удалит компилятор), но это более серьезная проблема, если выражение, которое нужно игнорировать, является чем-то вроде наблюдаемого поведения, такого как вызовы функций ввода-вывода или чтение и запись переменных volatile
.
Возникает интересный вопрос: можем ли мы принять выражение и полностью игнорировать его?
Вот что мы имеем сейчас:
#define USE(x) (void)(x)
// use iid in an expression to get rid of warning, but have no observable effect
USE(iid);
// hm, result of expression is gone but expression is still evaluated
USE(std::cout << "hmmm" << std::endl);
Это близко к решению:
// sizeof doesn't evaluate the expression
#define USE(x) (void)(sizeof(x))
Но сбой:
void foo();
// oops, cannot take sizeof void
USE(foo());
Решение состоит в том, чтобы просто:
// use expression as sub-expression,
// then make type of full expression int, discard result
#define USE(x) (void)(sizeof((x), 0))
Это не гарантирует работу. Забастовкa >
Изменить: Вышеупомянутое не гарантировало никакого эффекта, но я отправил его без тестирования. После тестирования он снова генерирует предупреждение, по крайней мере, в MSVC 2010, потому что значение не используется. Это нехорошо, время для более трюков!
Напоминание: мы хотим "использовать" выражение без его оценки. Как это может быть сделано? Вот так:
#define USE(x) ((void)(true ? 0 : (x)))
У этого есть простая проблема, как в прошлый раз (хуже на самом деле), в том, что (x)
необходимо преобразовать в int
. Это опять же тривиально для исправления:
#define USE(x) ((void)(true ? 0 : ((x), 0)))
И мы вернулись к тому же эффекту, который у нас был в прошлый раз (нет), но на этот раз x
"используется", поэтому мы не получаем никаких предупреждений. Готово, правильно?
На самом деле все еще есть одна проблема с этим решением (и он присутствовал и в последнем не-решении, но остался незамеченным), и он появляется в этом примере:
struct foo {};
void operator,(const foo&, int) {}
foo f;
USE(f); // oops, void isn't convertible to int!
То есть, если тип выражения (x)
перегружает оператор запятой чем-то, не конвертируемым в int
, решение не выполняется. Конечно, маловероятно, но ради того, чтобы полностью выйти за борт, мы можем исправить это:
#define USE(x) ((void)(true ? 0 : ((x), void(), 0)))
Чтобы убедиться, что мы действительно закончили с нулем. Этот трюк, представленный Йоханнесом.
Также как отмечено, если выше было недостаточно, достаточно глупый компилятор мог бы "загрузить" выражение 0
(в регистр или что-то еще), а затем проигнорировать его.
Я думаю, что невозможно избавиться от этого, так как в конечном итоге нам нужно выражение, которое приведет к тому, что какой-то тип игнорируется, но если я когда-нибудь подумаю об этом, я добавлю его.