不寻常的编译器错误转换为无效?

Unusual compiler error casting to void?

我正在为我正在教的 class 整理一个基于 C++ 的作业。我有一个函数要导出给学生,我希望他们在程序的不同点调用它,以便在评分期间,我们可以拦截这些调用以确保他们在正确的时间做正确的事情.我不希望该代码在提供的起始文件中执行任何操作,因此我只为该函数提供了一个主体,该主体仅包含一系列语句,这些语句将所有参数强制转换为 void 以抑制编译器关于未使用参数的警告。在这样做的过程中,我 运行 遇到了一个我以前从未见过的不寻常的编译器错误,并且对该站点的搜索没有找到任何有用的信息。

错误可以通过 this reduced test case:

得到最好的例证
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);

是一个包含 ab 的逗号表达式,然后使用函数式转换将其转换为类型 void。如您所见,以下变体都有效:

(void)(a, b);
void((a, b));

我怀疑这可能与 Most Vexing Parse 有关,这被解释为声明,但我遇到的特定错误似乎与此不符。

我的问题如下:

  1. 为什么这个代码不合法​​?
  2. 编译器认为我要做什么?
  3. 为什么这些其他变体是合法的?

在第 void(a, b); 编译器 "think" 行中,您试图将类型用作函数名称,因此它给出了错误。

其他情况是类型转换...

查看 documentation 我想您违反了转换案例规则之一 (#3):

If there are more than one expression in parentheses, new_type must be a class with a suitably declared constructor. This expression is a prvalue of type new_type designating a temporary (until C++17)whose result object is (since C++17) direct-initialized with expressions.

鉴于此结构:

struct S {
  S(int, int) {}
};

S(1, 2) 是什么意思?

答案:这意味着您从值 12.

构造一个类型 S 的对象

给出这个函数模板:

template <typename T> T f() { return T(1, 2); }

T(1, 2) 是什么意思?

答案:这意味着您从值 12 构造一个类型 T 的对象,如果 T 是类型 S 来自第一个问题。


给定相同的函数模板,那么 f<void>() 是什么意思?

答案:它试图从 12 这两个值构造一个 void 值。这失败了,因为只能将单个值转换为 void.


T 恰好是 void 时,void(1, 2)T(1, 2) 有什么不同吗?

答案:不,这两个意思完全一样,这就是错误的原因。