The conditional operator is described in 5.16 [expr.cond]. Its paragraph 2 includes the following text:
The second or the third operand (but not both) is a throw-expression (15.1); the result is of the type of the other and is a prvalue.
That says that it is allowed to throw an exception from the conditional operator. However, even if the other branch is an lvalue, it is turned into an rvalue! Thus, it isn't possible to bind an lvalue to the result of a conditional expression. Aside from rewriting the condition using the comma operator, the code could be rewritten to only obtain the lvalue from the result of the conditional operator:
template <typename It>
typename std::iterator_traits<It>::reference
access(It it, It end) {
return *(it == end? throw std::runtime_error("no element"): it);
}
The somewhat tricky business is that returning a const
reference from the function would compile but actually return a reference to a temporary!