【发布时间】:2021-10-17 06:15:38
【问题描述】:
众所周知,throw 可以作为 C++ 三元运算符?: 的第二个或第三个操作数。但它可以在操作数的逗号子表达式中吗?看起来编译器在这方面存在分歧。请考虑一个例子:
#include <iostream>
void foo(bool b) {
int i = b ? 1 : (throw 0); //ok everywhere
if ( !b )
(std::cout << "smth\n", throw 0); //ok everywhere
i = b ? 2 : (std::cout << "smth\n", throw 0); //ok in MSVC only
};
此示例被 MSVC 接受,但被 GCC 和 Clang 拒绝,演示:https://gcc.godbolt.org/z/6q46j5exP
虽然报错信息:
error: third operand to the conditional operator is of type 'void', but the second operand is neither a throw-expression nor of type 'void'
7 | i = b ? 2 : (std::cout << "smth\n", throw 0);
| ^
表明它不是故意拒绝的,而是编译器认为第三个操作数不仅具有正式类型void,而且实际上可以返回。
根据https://en.cppreference.com/w/cpp/language/operator_other,看来GCC/Clang是对的
E2 或 E3(但不是两者)是一个(可能带括号的)抛出表达式。
这里我们用括号括起来的逗号表达式以 throw-expression 结尾。
按照标准,MSVC在接受示例的最后一行是不正确的吗?
【问题讨论】:
-
仅供参考,并没有解释差异尝试
i = b ? 2 : (std::cout << "smth\n", throw 0, 42);这使得子表达式(E2和E3)的类型相同。 -
@RichardCritten,感谢您的想法。这确实被所有人接受:gcc.godbolt.org/z/85YGz9ffG
标签: c++ language-lawyer conditional-operator throw