noexcept specifier

C++ has automatic return type deduction since C++11. However, in C++20 there’s still no support for automatic noexcept specification. The following utilities make it easier to write noexcept-correct code until we get noexcept(auto) in the language.

One caveat worth noting when using these utilities is that operator noexcept(T{}) checks not only that the constructor is non-throwing, but also the destructor. Unfortunately, std::is_nothrow_constructible doesn’t help either (see Notes).

Reference

AC_DEDUCE_NOEXCEPT_AND_RETURN(...)

Macro that avoids code duplication by returning the given expression from the function and deducing the noexcept specification from it. For example, the following operator

template <class T>
bool operator > (T lhs, T rhs) noexcept(noexcept(rhs < lhs)) {
    return rhs < lhs;
} 
can be rewritten as
template <class T>
bool operator > (T lhs, T rhs)
    AC_DEDUCE_NOEXCEPT_AND_RETURN(rhs < lhs)

AC_DEDUCE_NOEXCEPT_DECLTYPE_AND_RETURN(...)

Macro that avoids code duplication by returning the given expression from the function and deducing the noexcept specification and return type from it. For example, the following operator

template <class T>
auto operator > (T lhs, T rhs) noexcept(noexcept(rhs < lhs))
    -> decltype(rhs < lhs) {
    return rhs < lhs;
} 
can be rewritten as
template <class T>
auto operator > (T lhs, T rhs)
    AC_DEDUCE_NOEXCEPT_DECLTYPE_AND_RETURN(rhs < lhs)
This macro is different from AC_DEDUCE_NOEXCEPT_AND_RETURN, because it correctly disables a function when the expression is ill-formed (SFINAE) instead of defining a function that always produces a compilation error.

AC_DEDUCE_NOEXCEPT_REQUIRES_AND_RETURN(...)

Macro for C++20 that avoids code duplication by returning the given expression from the function and deducing the noexcept specification and type requirements from it. For example, the following operator

template <class T>
bool operator > (T lhs, T rhs) noexcept(noexcept(rhs < lhs))
    requires requires { rhs < lhs; } {
    return rhs < lhs;
} 
can be rewritten as
template <class T>
bool operator > (T lhs, T rhs)
    AC_DEDUCE_NOEXCEPT_REQUIRES_AND_RETURN(rhs < lhs)
Unlike AC_DEDUCE_NOEXCEPT_DECLTYPE_AND_RETURN, this macro requires return type specification, which can make the declaration more clear.

AC_DEDUCE_NOEXCEPT_AND_INITIALIZE(...)

Macro that avoids code duplication by using the given expression as a member initializer list and deducing the noexcept specification from it. For example, the following constructor

Derived(int x) noexcept(noexcept(Base{x})) : Base{x} {}
can be rewritten as
Derived(int x) AC_DEDUCE_NOEXCEPT_AND_INITIALIZE(Base{x}) {}

Note

Data members aren’t supported, only base classes and delegated constructors.

Source code

Tests

Design

These utilities are inspired by BOOST_HOF_RETURNS.