c++c++23noexcept

Short-circuit in noexcept expressions


given the follow code:

// g++ main.cpp -std=c++23

#include <type_traits>

using namespace std;

template<typename P>
concept pointer_like = is_pointer_v<P> || requires (P p) { p.operator ->(); };

template<pointer_like P>
constexpr auto func(P p)
    noexcept(is_pointer_v<P> || noexcept(p.operator ->())) // error: 'int *' doesn't have 'operator ->'
{
    if constexpr (is_pointer_v<P>)
        return p;
    else
        return p.operator ->();
}

int main() {
    int i = 0;
    auto pi = func(&i); // error from here
}

https://godbolt.org/z/Gqq3W4o4h

It seems short-circuit is not performed in the noexcept expression:

noexcept(is_pointer_v<P> || noexcept(p.operator ->()))

My expectation is:

Is it something C++ standard is missing?


Solution

  • Each sub-expression in the noexcept must be valid individually/separately.

    You can use requires to achieve the desired effect/result as shown below:

    template<pointer_like P> constexpr auto func(P p)
        noexcept(requires { requires is_pointer_v<P> || noexcept(p.operator ->()); })
    {
        if constexpr (is_pointer_v<P>)
            return p;
        else
            return p.operator ->();
    }
    

    Working demo