C ++中的抛出和三元运算符
Posted
技术标签:
【中文标题】C ++中的抛出和三元运算符【英文标题】:Throw and ternary operator in C++ 【发布时间】:2011-12-18 22:50:57 【问题描述】:以下代码使用 G++ 4.6.1 编译,但不适用于 Visual Studio 2008
return (m_something == 0) ?
throw std::logic_error("Something wrong happened") : m_something;
事实上,Visual Studio 编译器执行了内部崩溃。
我想知道这是否是标准 C++,为什么它不能用 Visual Studio 编译,但用 G++ 编译?
【问题讨论】:
无论这是否是有效代码,根据标准,当编译器崩溃并出现内部编译器错误(这是 VC 所做的,IIUC)时,这就是编译器中的错误。即使是错误代码,编译器也应该发出有意义的消息,而不是崩溃报告。 记住这是条件运算符,恰好是a三元运算符。 是的,当规范中没有“三元”时感到困惑。 在一段短暂的时期内(在 c++11 和 c++14 之间),从三元抛出是编写可能在编译时失败的 constexpr 函数的唯一方法。 【参考方案1】:它是标准的 C++。条件表达式中的 then/else 表达式中的任何一个(或两个)都可以作为 throw 表达式(C++98 5.16/2)。
如果 Visual Studio 在编译时崩溃……那似乎很不幸!
【讨论】:
§5.16/2 允许这两个表达式都是 C++11 中的 throw 表达式。 @Mat:哎呀,你说的很对,这里的文字没有改变,第二种选择也允许在 C++98 中抛出。【参考方案2】:Comeau 编译它没有错误(这是我的最小可编译测试用例):
int main(void)
int x = 17;
return x ? throw "Something wrong happened" : 5;
这是标准允许的很好的证据。 MSVC 崩溃的事实也是如此,而不是完全失败并出现错误。
此外,它似乎已在 VC++ 2010 中修复
R:\>cl ternarythrowtest.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
ternarythrowtest.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:ternarythrowtest.exe
ternarythrowtest.obj
和 x64 版本:
R:\>cl ternarythrowtest.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
ternarythrowtest.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:ternarythrowtest.exe
ternarythrowtest.obj
如果可能的话,升级你的编译器,这远不是 2010 年修复的唯一错误。
【讨论】:
确实,这可能是因为符合 C++11,请参阅@MooingDuck 的回答。 @AndréCaron:这无法解释“内部编译器错误”。看看约翰的回答,它在 C++98 中也是允许的。 我在@fmorency 的团队中,我是遇到Microsoft Compiler 崩溃的人,他的throw-in-a-ternary-operator 表达式。我们试图弄清楚它是否是标准的,而不是这是否是 Microsoft 编译器中的错误(显然存在 a 错误,因为它崩溃了)。 @AndréCaron:嗯,它是 C++98,而不是 C++11 合规性问题,所以它肯定可以工作。 确实:-)。不幸的是,我们目前坚持使用 Qt 4.7,并且我们支持 Windows,所以我们坚持使用 VS2008 的编译器。【参考方案3】:来自 C++11 二月草案
§ 5.16/2 如果第二个或第三个操作数的类型(可能是 cv 限定的)void,则左值到右值 (4.1)、数组到指针 (4.2) 和函数到-指针 (4.3) 标准转换是在第二个和第三个操作数上执行的,并且应满足以下条件之一: — 第二个或第三个操作数(但不是两者)是 throw 表达式(15.1);结果是另一个的类型并且是prvalue。 — 第二个和第三个操作数都有 void 类型;结果是 void 类型并且是纯右值。 [ 注意:这包括两个操作数都是 throw 表达式的情况。 ——尾注]
看来throw
算作对void
的评估,这是允许的。
【讨论】:
C++11 与 VS2008 几乎没有关系(除了这不是 C++11 规则,自 C++98 以来它没有变化,请参阅约翰的回答)。 我没有要引用的 C++03 草案(用于 VS2008)的副本,否则我会引用它。没错,它不一定适用于 VS2008。【参考方案4】:内部崩溃可以认为是 Visual Studio 的一个错误。编译器不应该因为正在编译的代码而崩溃。
这是一个非常奇怪的三元运算符用法,在 return 之前简单的 if 会是一个更可取的习惯用法:
if(m_something == 0)
throw std::logic_error("Something wrong happened");
return m_something;
【讨论】:
以上是关于C ++中的抛出和三元运算符的主要内容,如果未能解决你的问题,请参考以下文章