Die*_*ühl 23 c++ constexpr c++11
有时候只需要一个语句(返回时就必须这样)是方便的,甚至是必要的constexpr.如果需要检查条件并且只允许一个语句,则条件运算符是唯一的选项.如果出现错误,最好从条件运算符中抛出异常,例如:
template <typename It>
typename std::iterator_traits<It>::reference
access(It it, It end) {
return it == end? throw std::runtime_error("no element"): *it;
}
Run Code Online (Sandbox Code Playgroud)
但是,当用作例如(实例)时,上述函数不会编译:
std::vector<int> v;
access(v.begin(), v.end());
Run Code Online (Sandbox Code Playgroud)
编译器抱怨尝试将非const引用绑定到临时.不过,编译器并没有抱怨throw-expression本身.所以问题是:可以从条件运算符抛出异常,如果是这样,上面的代码出了什么问题?
Die*_*ühl 16
条件运算符在5.16 [expr.cond]中描述.其第2款包括以下案文:
第二个或第三个操作数(但不是两个)是一个throw-expression(15.1); 结果是另一个的类型,是一个prvalue.
这表示允许从条件运算符抛出异常.但是,即使另一个分支是左值,它也会变成右值!因此,不可能将左值绑定到条件表达式的结果.除了使用逗号运算符重写条件之外,可以重写代码以仅从条件运算符的结果中获取左值:
template <typename It>
typename std::iterator_traits<It>::reference
access(It it, It end) {
return *(it == end? throw std::runtime_error("no element"): it);
}
Run Code Online (Sandbox Code Playgroud)
有点棘手的事情是const从函数返回一个引用会编译,但实际上返回一个临时的引用!
Dav*_*eas 13
标准中的措辞大约是5.16/2:
如果第二个或第三个操作数的类型为void,则在第二个和第三个上执行左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换操作数,以下之一应包含:
- 第二个或第三个操作数(但不是两个)是一个throw-expression(15.1); 结果是另一个的类型,是一个prvalue.
这解释了你的行为.抛出是合法的,但表达式的类型是纯rvalue(即使表达式是左值),因此你不能绑定非const 左值引用
Dan*_*rey 12
它可以这样做:
return it == end? (throw std::runtime_error("no element"),*it): *it;
Run Code Online (Sandbox Code Playgroud)