C++ BOOST_THROW_异常';初始化列表中缺少三元运算符

C++ BOOST_THROW_异常';初始化列表中缺少三元运算符,c++,exception,boost,initialization-list,C++,Exception,Boost,Initialization List,我经常使用ternaries抛出异常,这可能看起来有点奇怪,但可以在初始化列表中节省时间(因此这有助于编写声音构造函数,因此有助于RAII…)。例如,如果参数a是我们想要非nullptr的smart\u ptr,那么我可以启动一个成员,如 member(a ? a->get_something() : throw exception()) 我认为这是一种有效、合法和安全的使用方法(如果不是,请告诉我) 我最近切换到boost::exception,不幸的是条件?ret\u值:BOOST\

我经常使用ternaries抛出异常,这可能看起来有点奇怪,但可以在初始化列表中节省时间(因此这有助于编写声音构造函数,因此有助于RAII…)。例如,如果参数
a
是我们想要非
nullptr
smart\u ptr
,那么我可以启动一个成员,如

member(a ? a->get_something() : throw exception())
我认为这是一种有效、合法和安全的使用方法(如果不是,请告诉我)

我最近切换到boost::exception,不幸的是
条件?ret\u值:BOOST\u THROW\u异常(EXCEPTION())
不编译(因为编译器无法具体化
typeof(ret\u值)
void

有没有比创建一个全新的私有静态方法并将
if
放入其中更好的解决方法

我认为这是一种有效、合法和安全的使用方法(如果不是,请告诉我)

事实并非如此,依我看。你不能也不应该为你可能得到的任何蹩脚论点辩护。因为如果你愿意,你必须检查所有的东西。如果任何
size\u t
函数参数包含合理的值,则必须对其进行检查。任何
char*
都必须检查它是否为NULL,如果不是,则必须检查它是否以零分隔。您必须在整个类和函数中应用数千次检查,以检查不太可能发生但在某些奇怪情况下可能发生的事情

考虑
std::strlen
std::string::string(char const*)
:两者都要求参数是指向以null结尾的字符字符串的非null指针。未应用任何检查,如果通过NULL,则得到UB

在许多情况下,函数保证返回非空指针。如果将这样的结果传递给构造函数(或strlen),那么额外的检查将浪费时间和编程工作。

简而言之:不要测试空指针,只需要非空指针。客户端的责任是传递正确的参数,因为只有客户端代码知道是否需要检查零指针,并且无论如何都必须处理Null指针的情况,无论是通过调用之前检查还是通过捕获异常。

< P>这是完全有效的C++。但许多编译器不会将BOOST_THROW_异常视为一个THROW表达式,而只是一个常规的void类型表达式。由于标准要求void类型表达式要么是抛出表达式,要么两个分支都是void类型,编译器拒绝使用三元表达式

典型的解决方法是使用逗号运算符:

condition ? ret_value : (BOOST_THROW_EXCEPTION(exception()), decltype(ret_value){})

当然,您可以用任何正确类型的表达式替换逗号后面的部分,您可以确定它不会被使用。

我不确定我是否同意这种方法。有时会出现一些不可预见的情况,而这些情况恰恰是例外。也许共享的例子太简单了,但是条件本身可能非常复杂或棘手,以至于调用者不知道该怎么做(比如测试矩阵是否为满秩)。此外,这不是一个面向外部的API,而是一个大型的关键项目(在不能失败的意义上是关键的),我学会了不要相信自己有未经检查的先决条件:有一天它不起作用,但看起来它起作用了,灾难迫在眉睫。我想这是一个有趣的事情……如果条件很复杂,这意味着三元表达式将足够复杂,它应该放在自己的
initMemberFromA
-函数中。无论它是否是外部API都不相关-在调用内部API时必须像调用标准库功能一样小心。对于
不能失败的
模块,必须具备与任何其他模块相同的功能:广泛的单元测试和良好的代码审查。如果仍要检查参数,请在函数中进行检查。初始值设定项应该是单个表达式以保持可读性。这个怎么样
m_det(a->isFullRank()?a->行列式():抛出异常()),m_X(m_det->ispureImaginate()?m_det->imaginaryPart():抛出异常())
现在测试可能很复杂,但可读性很强。此外,我还将另一个潜在的复杂测试链接到它,但它仍然使用初始化列表,并且可以继续进行。总的来说,你可能是对的,但我知道我很邋遢,这就是为什么我喜欢给自己额外的幼儿酒吧。我不认为这很易读。这个怎么样:
m_det(getdeterminate(a))、m_X(getpureImaginate(m_det))
或者
m_X
m_det
如果它们关系如此密切,那么它们应该一起填充到一个公共子对象中,但这在很大程度上取决于上下文。
decltype{}
decltype
是一个运算符,您是否考虑使用
std::declval
?在这种情况下,这也不起作用:
std::declval
只能出现在未计算的上下文中。
decltype(ret_值)
将返回
ret_值的类型
,以下
{}
将默认构造该类型的值。如果您知道返回值的类型,通常最好提供实际值。我刚才用了
decltype
来概括一下。你说得对。尽管我几分钟前拼写正确,但我还是以某种方式打错了。