条件演算子の戻り値にはthrow-expressionを書くことが出来る

5.16 Conditional operator
If either the second or the third operand has type void, then the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the second and third operands, and one of the following shall hold:
— 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.
— Both the second and the third operands have type void; the result is of type void and is a prvalue.
[ Note: This includes the case where both operands are throw-expressions. — end note ]

大学で小さな勉強会を開いたのですが、条件演算子の戻り値となる部分にthrowを書くことが出来るというのは意外と知られていませんでした。
良い機会だったので、帰宅してから規格を確認し直しました。
条件演算子の戻り値部分(二項め又は三項め)がthrowであった場合、他方が型を持っていれば、戻り値の型は他方の型になります。
両方がthrowであれば、戻り値の型はvoid型となります。

実用例

#include <type_traits>
#include <stdexcept>
#include <cassert>

template <class T, std::size_t N>
struct ctarray
{
    T value[N];
    constexpr T operator[](const std::size_t n) const { return value[n]; }
    constexpr T at(const std::size_t n) const
    {
        return n < N ? value[n] : throw std::out_of_range("out of range");
    }
    constexpr std::size_t length() const { return N; }
    constexpr std::size_t size() const { return N; }
};
 
int main()
{
    constexpr ctarray<int, 5> tmp{{0, 1, 2, 3, 4}};
    static_assert(tmp.at(0) == 0, "");
    assert(tmp.at(0) == 0);
}

このようなコンパイル時、実行時両方で使える配列型を定義するとします。
atメンバ関数は範囲チェック付きの要素アクセスを行う関数です。
範囲チェックにstatic_assertを用いた場合、atメンバ関数はコンパイル時には使えますが、実行時に使えなくなってしまいます。
条件演算子を用いて範囲外の場合にout_of_rangeをthrowするようにすれば、コンパイル時にはコンパイルエラー、実行時には例外にすることが出来ます。
C++14以降では条件チェックにif文などを使う事も出来ますが、条件演算子からthrow出来る事は知っておくべきだと思います。