Да, но вы, вероятно, получите еще одно предупреждение.
Стандартный способ сделать это: (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))
Что гарантирует отсутствие операции.
Редактировать: Вышесказанное действительно не гарантировало никакого эффекта, но я разместил без тестирования. После тестирования он снова выдает предупреждение, по крайней мере, в 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
(в регистр или что-то в этом роде), а затем проигнорировать его.
Я думаю, что от этого невозможно избавиться, поскольку в конечном итоге нам нужно выражение, которое приведет к некоторому типу игнорирования, но если я когда-нибудь подумаю об этом, я добавлю его.