我正在为我正在教的一门课编写一份基于C++的作业。我有一个函数正在导出给学生,我希望他们在课程的各个阶段调用该函数,这样,在评分过程中,我们可以拦截这些调用,以确保他们在正确的时间做正确的事情。我不希望这些代码在提供的启动文件中做任何事情,所以我只是给函数一个主体,它只有一系列语句,将所有参数强制转换为void
,以抑制编译器对未使用参数的警告。在这样做的过程中,我遇到了一个前所未有的异常编译器错误,在这个网站上搜索也没有发现任何帮助。
这个简化的测试用例可以最好地说明错误:
void iDontUseMyArguments(int a, int b) {
(void) a; // Explicit cast to void - totally fine!
(void) b;
}
void iDontEither(int a, int b) {
(void) a, b; // Comma expression casted to void, though technically
// b isn't casted to void!
}
void norDoI(int a, int b) {
void(a, b); // ERROR! No idea why this isn't okay.
}
void meNeither(int a, int b) {
(void)(a, b); // Comma expression casted to void - totally fine!
}
void jumpOnBandwagon(int a, int b) {
void((a, b)); // Comma expression casted to void - totally fine!
}
正如您所看到的,大多数编译都很好。问题就在这个:
void(a, b);
这会触发以下错误:
prog.cpp: In function 'void norDoI(int, int)':
prog.cpp:11:11: error: expression list treated as compound expression in functional cast [-fpermissive]
void(a, b);
^
我从来没有遇到过这个错误消息,所以我不确定这是想告诉我什么。
背后的意图
void(a, b);
是一个包含a
和b
的逗号表达式,然后使用函数样式转换将其转换为类型void
。正如你所看到的,以下变体都有效:
(void)(a, b);
void((a, b));
我怀疑这可能与Most Vexing Parse有关,这被解释为一个声明,但我得到的特定错误似乎与此不匹配。
我的问题如下:
- 为什么这个代码不合法
- 编译器认为我要做什么
- 为什么这些其他变体是合法的
给定此结构:
struct S {
S(int, int) {}
};
S(1, 2)
是什么意思?
答:这意味着您根据值1
和2
构造了一个类型为S
的对象。
给定此函数模板:
template <typename T> T f() { return T(1, 2); }
T(1, 2)
是什么意思?
答:这意味着您根据值1
和2
构造一个类型为T
的对象,例如,如果T
是第一个问题中的类型S
,则这是可能的。
给定相同的函数模板,那么f<void>()
意味着什么?
答:它试图从两个值1
和2
构造一个单独的void
值。这失败了,因为只有单个值可以转换为void
。
当T
恰好是void
时,void(1, 2)
与T(1, 2)
有什么不同吗?
答:不,意思完全一样,这就是为什么它是一个错误。
查看文档,我认为您违反了转换案例规则(#3)之一:
如果括号中有多个表达式,则new_type必须是具有适当声明的构造函数的类。此表达式是new_type类型的prvalue,指定临时(直到C++17),其结果对象(从C++17开始)直接用表达式初始化。
在第void(a, b);
行中,编译器"认为"您正试图使用类型作为函数名,因此它给出了一个错误。
其他情况是类型铸造。。。