0%

Exceptions in constexpr Functions in C++

This is my learning notes from the course - Mastering C++ Standard Library Features.

Exceptions in constexpr Functions

  • How exceptions and throw interact with constexpr functions
  • Use case examples

The Rule

  • The C++ Standard mentions that try-catch block are not allowed in constexpr functions
    • This means that you will not be able to catch exceptions
  • However, throw expressions are allowed
    • What does it mean to throw an exception at compile-time?

Example: Throw in a constexpr Function

1
2
3
4
5
6
7
8
9
constexpr int foo(int x)
{
if(x < 0)
{
throw std::runtime_error{"`x` must be positive"};
}

return x;
}
  • foo(x) throws if x < 0, otherwise returns x
1
2
3
4
5
6
int main()
{
int i;
std::cin >> i;
foo(i);
}
  • When executed at run-time, foo behaves as expected:
    • if i >= 0, no exception will be thrown and the program will exit gracefully
    • if i < 0, an exception will be thrown and std::terminate will be invoked
1
2
3
4
int main()
{
constexpr auto result = foo(-5);
}
  • When executed at compile-time with a negative value, the program will not compile:

    Error: constexpr variable ‘result’ must be initialized by a constant expression

    1
    2
    constexpr auto result = foo(-5);
    ^ ~~~~~~~
1
2
3
4
5
6
7
8
9
constexpr int foo(int x)
{
if(x < 0)
{
throw std::runtime_error{"`x` must be positive"};
}

return x;
}
  • If a code path hits a throw expression during compile-time evaluation, the program will fail to compile
  • Otherwise, the program will compile

Example: Rejecting Negative Values in Factorial

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
constexpr int factorial(int n)
{
if(n < 0)
{
throw std::runtime_error{"`n` must be positive"};
}

int result = 1;
for(int i = 1; i <= n; i++)
{
result *= i;
}

return result;
}

Example: Rejecting Invalid Strings

1
2
3
4
5
6
7
8
9
constexpr bool is_user_id(std::string_view id)
{
if(id.size() < 3)
{
throw std::runtime_error{"Invalid id format"};
}

return id[0] == 'U' && id[1] == ".";
}

Summary

  • Try-catch blocks cannot appear in constexpr functions
  • throw expressions can appear in constexpr functions
  • During compile-time evaluation of a constexpr function, compilation will only fail if a throw expression is hit

Guidelines

  • Consider using throw in constexpr functions that can fail depending on some conditions tested on the input arguments
    • During run-time evaluation, the exception must be caught and properly handled
    • During compile-time evaluation, you will get an helpful compiler error message
  • To check preconditions, prefer assert to throw
    • assert is allowed in constexpr functions since C++17

Section Summary

  • Learned that constant expressions are expressions that can be evaluated at compile-time
  • Studied that constexpr functions can be evaluated both at compile-time and run-time
  • Understood that C++14 constexpr functions are very flexible compared to C++11
  • Understood that the Standard Library does not provide many constexpr utilities, but it will in the near future
  • Learned that you cannot catch exceptions in constexpr functions, but you can have throw expressions in them. They will cause a compile-time error in case a code path hits them during evaluation