在C++中,有时会定义一个变量,但不会使用。这是一个示例-与 COM_INTERFACE_ENTRY_FUNC_BLIND ATL宏一起使用的函数:

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;
}

在上面的示例中,iid参数与DEBUG_LOG宏一起使用,该宏在非调试配置中扩展为空字符串。因此,注释掉或删除签名中的iid变量名称不是一种选择。在编译非调试配置时,编译器会生成C4100: 'iid' : unreferenced formal parameter警告,因此,为了使警告静音,将添加被认为是no-op的iid;语句。

问题如下:如果我们有以下任何声明:
 CSomeType variableName; //or
 CSomeType& variableName; //or
 CSomeType* variableName;

将在C++代码中执行以下语句:
variableName;

无论什么时候CSomeType是什么,都必须时刻保持无操作状态?

最佳答案

是的,但是您可能会再次收到警告。

执行此操作的标准方法是:(void)iid;

从技术上讲,这仍然可以将iid加载到寄存器中,并且什么也不做。当然,在编译器方面这是非常愚蠢的(如果删除了编译器,我怀疑有人会这样做),但是如果要忽略的表达式涉及可观察到的行为(例如,对IO函数的调用或读写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)))

为确保我们最终得到零。 This trick brought to you by Johannes

还要注意的是,如果以上操作还不够,那么足够愚蠢的编译器可能会将表达式0(装入寄存器或其他内容)“加载”,然后忽略它。

我认为这是不可能消除的,因为我们最终需要一个表达式来导致某种类型的类型被忽略,但是如果我想到了,我会添加它。

10-05 23:00