4

I've implemented a smart pointer that stores an object of type T with proxy function that calls the internal object's methods:

template <class Function, class ...Args, class ...Params> 
inline bool call( Function (T::*function)(Args...) const, Params&& ...args ) const noexcept( noexcept( function ));

But I have found a strange problem - when an std::exception is generated in a member function, the program is terminated, even though the proxy function is called within a try block. So my question is: is it a correct way to use noexcept operator, and if not, how should I use it in this case?

Micha
  • 5,117
  • 8
  • 34
  • 47
Pavel Davydov
  • 3,379
  • 3
  • 28
  • 41
  • What's wrong with the smart pointers already in C++11 and/or `std::function`? – Some programmer dude Aug 09 '13 at 15:46
  • It uses copy on write in some special cases. And it makes all calls to the stored object thread safe. – Pavel Davydov Aug 09 '13 at 15:50
  • See [here](http://en.cppreference.com/w/cpp/language/noexcept_spec), particularly "If a function marked `noexcept` allows an uncaught exception to escape at runtime, `std::terminate` is called immediately. " – juanchopanza Aug 09 '13 at 15:52
  • Yeah, thanks, but neither T::function, nor this proxy call is marked noexcept, as far as I understand. I thought that noexcept operator would detect that member function can throw, cause it is not marked noexcept.. – Pavel Davydov Aug 09 '13 at 15:55

1 Answers1

4

Per C++11 §5.3.7/1:

The noexcept operator determines whether the evaluation of its operand, which is an unevaluated operand (Clause 5), can throw an exception (15.1).

Evaluating the expression (function) cannot throw an exception, so noexcept(function) evaluates to true. Note that this is not the same as evaluating the expression (*function)(std::forward<Params>(args)...), noexcept((*function)(std::forward<Params>(args)...)) would certainly evaluate to false, since the member function pointer is not qualified noexcept.

noexcept is a qualification on function pointer types like const. Since the function pointer type call accepts is NOT noexcept-qualified, that complicated noexcept(noexcept(...)) will always evaluate as noexcept(false).

EDIT: The below is incorrect, it's not possible to overload purely on the basis of noexcept qualification of a function pointer since "An exception-specification is not considered part of a function’s type." (§15.4/13)

If you want call to be noexcept when given a noexcept-qualified member function pointer, you need to provide an overload call(R (T::*)() const noexcept, ...).

Casey
  • 41,449
  • 7
  • 95
  • 125
  • Thanks for you answer! So should I use it like this - noexcept( noexcept( *function(std::forward(args)...)) ? – Pavel Davydov Aug 09 '13 at 16:01
  • 2
    @PavelDavydov Yep, that's correct. It really gets fun when you have the exact same expression in the `noexcept` clause, in the trailing return type, and in the function body ;) `auto foo(...) -> decltype(expr) noexcept(noexcept(expr)) { return expr; }` – Casey Aug 09 '13 at 16:02
  • Looks cool =). I was thinking for a while how to make it work with functions that have a return type different from bool, now I know it, thanks! – Pavel Davydov Aug 09 '13 at 16:08
  • @PavelDavydov Clarified in my answer that for your specific case, `call` can never be `noexcept`. – Casey Aug 09 '13 at 16:22
  • @PavelDavydov Clarified again that I am a dirty lying liar and it's not possible to overload on `noexcept` alone. – Casey Aug 09 '13 at 16:47