Puzzle #9 (based on C++17)

constexpr int foo(int value)
{
  return value < 13 ? value * 2
                    : throw 0;
}

int main()
{
  try
  {
    constexpr auto v = foo(10);
    return v;   
  }
  catch(int val)
  {
    return val;
  }
}

With given code and C++17 compiler, pick one answer:

  • Guaranteed to return 0 from main.
  • Guaranteed to return 20 from main.
  • Guaranteed to return something other from main.
  • Undefined behavior.
  • Implementation defined.
  • Will not compile.
Click here for the answer

The correct answer is: Guaranteed to return 20 from main.

Wait what? throw in a constant expression? Let’s dive into [expr.const]/2

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions: … and there is a long list of forbidden expressions…

The part that interests us is:

following the rules of the abstract machine

We can throw and do bunch of other stuff in foo() as long as following the rules of the abstract machine it will still be a constant expression. E.g. this will fail to compile:

constexpr int foo(int value)
{
  return value < 13 ? value * 2
                    : throw 0;
}

int main()
{
  try
  {
    constexpr auto v = foo(42);
    return v;   
  }
  catch(int val)
  {
    return val;
  }
}

because value < 13 will not be fulfilled, abstract machine will go further and run into a throw expression, which is forbidden in constant expression.

Thanks for reading o/