7

I mistakenly pasted a throw statement after a return with the following final result:

void DXManager::initialize(const std::shared_ptr<nae::Context>& ctx_ptr)
{
    // ...

    if (FAILED(result))
    {
        return throw std::exception("Failed to enumerate display mode list");
    }

    // ...
}

I successfully built the solution before noticing the mistake, and I'm curious which specification allows the syntax above.


By reading cppreference.com (under Notes), I see

The throw-expression is classified as prvalue expression of type void. Like any other expression, it may be a sub-expression in another expression, most commonly in the conditional operator:

double f(double d)
  {
      return d > 1e7 ? throw std::overflow_error("too big") : d;
  }
  // ...

but I'm not quite sure it's what I'm looking for.

payloc91
  • 3,724
  • 1
  • 17
  • 45
  • related/dupe: https://stackoverflow.com/questions/3383090/is-returning-void-valid-code – NathanOliver Aug 28 '18 at 13:52
  • 1
    @StoryTeller's answer to your question is perfectly correct, but regarding the example from cppreference.com: that case is explicitly allowed by the standard [C++14: 5.16/2]: _If either the second or the third operand has type void, one of the following shall hold: The second or the third operand (but not both) is a throw-expression; the result is of the type and value category of the other._ Normally if only one of the second and third operands to a ternary conditional were of void type the code would be invalid, but `throw` is a special case. – deltacrux May 11 '19 at 10:06

1 Answers1

6

Well, it's because a return statement in a function returning void, can have a void operand:

[stmt.return]/2

The expr-or-braced-init-list of a return statement is called its operand [...] A return statement with an operand of type void shall be used only in a function whose return type is cv void.

And as you found out yourself, a throw expression has type void. This provision is there to make writing generic code smoother. Consider this:

template<typename T>
T foo() {
    return T();
}

The above rule (along with another rule that defines void()) make the above template valid even when instantiated for void.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458