c++c++17overloadingoverload-resolutionnoexcept

Wouldn't it make sense to overload with respect to noexcept?


I am trying to understand the noexcept feature. I know it could be confusing, but besides that, could noexcept be deduced from the calling function when possible?

This is a non-working example of this situation,

void f(){}
void f() noexcept{} // not allowed in c++

void g(){f();} // should call f
void h() noexcept{f();} // should call f noexcept
int main(){
    g();
    h();
}

If the calling function (h) does not have a try/catch block, the compiler could deduce that the user is interested in calling a particular f.

Is this pattern used in some other workaround form?

All I can imagine is something like this, but it is not very generic:

template<bool NE> void F() noexcept(NE);

template<>
void F<true>() noexcept(true){}
template<>
void F<false>() noexcept(false){}

void g(){F<noexcept(g)>();} // calls F<false>
void h() noexcept{F<noexcept(h)>();} // call F<true>

Some may wonder why that would make sense. My logic is that C++ allows overloading with respect to const, both an argument of functions and a member function. For example, const member functions prefer to call const member overloads.

I think it would make sense for noexcept functions to call noexcept "overloads," especially if they are not called from a try/catch block.


Solution

  • It makes sense,

    Of course it would make sense in principle. One version of the function could run, say, a faster algorithm, but which requires dynamically-allocated extra scratch memory, while the noexcept version could use a slower algorithm with O(1) extra space, on the stack.

    but you wouldn't be able to resolve the overload ...

    As you may know, it's perfectly valid to call noexcept(false) functions from noexcept(true) functions. You're just risking a terminate() instead of an exception being thrown; and sometimes - you're not risking anything because you've verified that the inputs you pass cannot trigger an exception. So, how would the compiler know which version of the function you're calling? And the same question for the other direction - maybe you want to call your noexcept(true) function from within a noexcept(false) function? That's also allowed.

    ... and - it would be mostly syntactic sugar anyway

    With C++11, you can write:

    #include <stdexcept>
    
    template <bool ne2>
    int bar(int x) noexcept(ne2);
    
    template<> int bar<true>(int) noexcept { return 0; }
    template<> int bar<false>(int) { throw std::logic_error("error!"); }
    

    and this compiles just fine: GodBolt.

    So you can have two functions with the same name and same arguments, differing only w.r.t. their noexcept value - but with different template arguments.