Will a "variableName;" C++ statement be a no-op at all times?

c++, compiler-warnings

Solution

Yes, but you'll likely get another warning.

The standard way of doing this is: `(void)iid;`.

Very technically, this could still load `iid` into a register and do nothing. Granted that's extremely stupid on the compilers part (I doubt any would ever do that, if it does delete the compiler), but it's a more serious issue if the expression to be ignored is something concerning observable behavior, like calls to IO functions or the reading and writing of `volatile` variables.

This brings up an interesting question: Can we take an expression and completely ignore it?

That is, what we have now is this:

#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);

This is close to a solution:

// sizeof doesn't evaluate the expression
#define USE(x) (void)(sizeof(x))

But fails with:

void foo();

// oops, cannot take sizeof void
USE(foo());

The solution is to simply:

// use expression as sub-expression,
// then make type of full expression int, discard result
#define USE(x) (void)(sizeof((x), 0))

Which guarantees no operation.

Edit: The above indeed guaranteed no effect, but I posted without testing. Upon testing, it generates a warning again, at least in MSVC 2010, because the value isn't used. That's no good, time for more tricks!

Reminder: We want to "use" an expression without evaluating it. How can this be done? Like this:

#define USE(x) ((void)(true ? 0 : (x)))

This has a simple problem like last time (worse actually), in that `(x)` needs to be be convertible to `int`. This is, again, trivial to fix:

#define USE(x) ((void)(true ? 0 : ((x), 0)))

And we're back to same kind of effect we had last time (none), but this time `x` is "used" so we don't get any warnings. Done, right?

There is actually still one problem with this solution (and was present in the last un-solution as well, but went unnoticed), and it comes up in this example:

struct foo {};
void operator,(const foo&, int) {}

foo f;
USE(f); // oops, void isn't convertible to int!

That is, if the type of the expression `(x)` overloads the comma operator to something not convertible to `int`, the solution fails. Sure, unlikely, but for the sake of going completely overboard, we can fix it with:

#define USE(x) ((void)(true ? 0 : ((x), void(), 0)))

To make sure we really end up with zero. This trick brought to you by Johannes.

Also as noted, if the above wasn't enough, a stupid enough compiler could potentially "load" the expression `0` (into a register or something), then disregard it.

I think it's impossible to be rid of that, since we ultimately need an expression to result in a type of some sort to ignore, but if I ever think of it I'll add it.

Problem

In C++ sometimes a variable will be defined, but not used. Here's an example - a function for use with `COM_INTERFACE_ENTRY_FUNC_BLIND` ATL macro: ``` HRESULT WINAPI blindQuery( void* /*currentObject*/, REFIID iid, void** ppv, DWORD_PTR /*param*/ ) { DEBUG_LOG( __FUNCTION__ ); //DEBUG_LOG macro expands to an empty string in non-debug DEBUG_LOG( iid ); iid; // <<<<<<<----silence compiler warning if( ppv == 0 ) { return E_POINTER; } *ppv = 0; return E_NOINTERFACE; } ``` In the above example `iid` parameter is used with `DEBUG_LOG` macro that expands into an empty string in non-debug configurations. So commenting out or removing the `iid` variable name in the signature is not an option. When non-debug configurations are being compiled the compiler spawns a `C4100: 'iid' : unreferenced formal parameter` warning, so in order to silence the warning the `iid;` statement that is believed to be a no-op is added. The question is the following: if we have any of the following declarations: ``` CSomeType variableName; //or CSomeType& variableName; //or CSomeType* variableName; ``` will the following statement in C++ code: ``` variableName; ``` be a no-op at all times independent of what `CSomeType` is?

Original source

Related problems