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

#include <actl/functional/noexcept/AC_DEDUCE_NOEXCEPT_AND_RETURN.hpp>
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<typename T>
bool operator > (T l, T r) noexcept(noexcept(r < l)) {
    return r < l;
}
can be rewritten as
template<typename T>
bool operator > (T l, T r)
    AC_DEDUCE_NOEXCEPT_AND_RETURN(r < l)

#include <actl/functional/noexcept/AC_DEDUCE_NOEXCEPT_DECLTYPE_AND_RETURN.hpp>
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<typename T>
auto operator > (T l, T r) noexcept(noexcept(r < l))
    -> decltype(r < l) {
    return r < l;
}
can be rewritten as
template<typename T>
auto operator > (T l, T r)
    AC_DEDUCE_NOEXCEPT_DECLTYPE_AND_RETURN(r < l)
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.

#include <actl/functional/noexcept/AC_DEDUCE_NOEXCEPT_REQUIRES_AND_RETURN.hpp>
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<typename T>
bool operator > (T l, T r) noexcept(noexcept(r < l))
    requires requires { r < l; } {
    return r < l;
}
can be rewritten as
template<typename T>
bool operator > (T l, T r)
    AC_DEDUCE_NOEXCEPT_REQUIRES_AND_RETURN(r < l)
Unlike #AC_DEDUCE_NOEXCEPT_DECLTYPE_AND_RETURN, this macro requires return type specification, which can make the declaration more clear.

#include <actl/functional/noexcept/AC_DEDUCE_NOEXCEPT_AND_INITIALIZE.hpp>
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.

See tests at tests/functional/noexcept/

Design

These utilities are inspired by BOOST_HOF_RETURNS.