我正在尝试学习可变参数模板和函数.我无法理解为什么这段代码不能编译:
template<typename T>
static void bar(T t) {}
template<typename... Args>
static void foo2(Args... args)
{
(bar(args)...);
}
int main()
{
foo2(1, 2, 3, "3");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我编译它失败时出现错误:
错误C3520:'args':必须在此上下文中扩展参数包
(在功能上foo2).
在C++中,有时会定义一个变量,但不会使用.这是一个示例 - 与COM_INTERFACE_ENTRY_FUNC_BLINDATL宏一起使用的函数:
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;
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,iid参数与DEBUG_LOG宏一起使用,在非调试配置中扩展为空字符串.因此,iid不能选择在签名中注释或删除变量名称.当编译非调试配置时,编译器会产生C4100: 'iid' : unreferenced formal parameter警告,因此为了使警告静音iid;,添加了被认为是无操作的语句.
问题如下:如果我们有以下任何声明:
CSomeType variableName; //or
CSomeType& variableName; //or
CSomeType* variableName;
Run Code Online (Sandbox Code Playgroud)
将在C++代码中的以下语句:
variableName; …Run Code Online (Sandbox Code Playgroud) 为什么以下程序
#include <iostream>
struct C
{
operator int()
{
std::cout << "C::operator int()" << std::endl;
return 0;
}
operator void()
{
std::cout << "C::operator void()" << std::endl;
}
};
int main()
{
C c;
(int)c;
(void)c;
// this does run the function:
// c.operator void();
}
Run Code Online (Sandbox Code Playgroud)
输出这个
C::operator int()
Run Code Online (Sandbox Code Playgroud)
而不是这个?
C::operator int()
C::operator void()
Run Code Online (Sandbox Code Playgroud)
一如既往,直接的回答是"因为标准是这么说的".
C++ 11标准,§12.3.2
转换函数从不用于将(可能是cv限定的)对象转换为(可能是cv限定的)相同的对象类型(或对它的引用),转换为该类型的(可能是cv限定的)基类(或引用它)或(可能是cv-qualified)void.
那么为什么标准会这样说呢?使空洞转换功能成为特殊情况有什么好处?
其他说明见脚注116:
这些转换被视为标准转换,用于重载解析(13.3.3.1,13.3.3.1.4),因此初始化(8.5)和显式转换(5.2.9).转换为void不会调用任何转换函数(5.2.9).即使从未直接调用执行转换,也可以声明此类转换函数,并且可以通过调用基类中的虚拟转换函数来实现.
我只是习惯于(void)对有关未使用变量的编译器警告进行静音.它看起来基本上也是其他人使用它的东西.
如果void转换函数遵循典型的转换函数规则,则可能会出现意外情况,但对于任何具有副作用的转换函数而言都是如此,并且创建这些意外将由程序员自行决定.
在任意类型上执行SFINAE时,通常需要将表达式的结果转换为void.我已经看到了两种方法; 演员无效:
(void)(expr) // or static_cast<void>(expr)
Run Code Online (Sandbox Code Playgroud)
或者,使用带有void prvalue RHS的逗号运算符:
(expr), void()
Run Code Online (Sandbox Code Playgroud)
我的理解是,在两种情况下都要expr评估(对于良好的形式,在非评估的上下文中)和结果(或结果类型,在非评估的上下文中)被丢弃; 在任何一种情况下,即使是病理类也不可能T覆盖T::operator void()或operator,(T, void).(参见:为什么是"运营商无效"不投语法调用?,什么的'无效()'中的'自动F(PARAMS) - > decltype(...,无效())'呢?).
也就是说,这两个成语是等价的,还是在某种情况下,一个人应该优先于另一个(可能是非标准的编译器)?如果没有,是否有任何理由(例如可理解性)偏好一个而不是另一个?