1
struct test {
    int var;

    consteval test(int i) : var{i}
    {
        static_assert(i == 3);
    }
};

int main()
{
    constexpr test t{3};
}

This is rejected with:

$ g++ c.cpp -std=c++20
c.cpp: In constructor ‘consteval test::test(int)’:
c.cpp:8:25: error: non-constant condition for static assertion
    8 |         static_assert(i == 3);
      |                       ~~^~~~
c.cpp:8:23: error: ‘i’ is not a constant expression
    8 |         static_assert(i == 3);
      |                       ^

Why can't I use static_assert if the constructor is guaranteed to be evaluated at compile time ?

1
  • 5
    parameters are never constant expressions. Commented Dec 19, 2024 at 14:27

2 Answers 2

5

It doesn't work that way.

When you write static_assert(i == 3); in the function definition, then you are asking the compiler to check that condition to be true while compiling the definition of the function. At that point i is not known.

Formally, i == 3 must itself be a constant expression, but i is not usable in constant expressions because it is not a compile-time constant (function parameters never are).

Sign up to request clarification or add additional context in comments.

2 Comments

You say: "At that point i is not known".. Do you have an example of creating a test object where the compiler cannot deduce the value of i ?
@curiousguy12 The assertion is checked on the definition of the function, not when an object is created.
3

Function parameters are not usable as constant expressions. If you want to do compile-time checking you can try to do some workarounds though.

Take this code for example:

consteval void static_assert_num(auto number_to_check, int asserted_value)
{
    number_to_check /= (number_to_check == asserted_value);    
}

struct test {
    int var;

    consteval test(int i) : var{i}
    {
        static_assert_num(i, 3);
    }
};

int main()
{
    constexpr test t{3}; // no error
    constexpr test t{4}; // compilation error
}

Not the cleanest code, and maybe someone can come up with something better, but this seems to do the job. We can abuse the fact that constexpr doesn't allow for UB, so we just divide by zero to force an error (more examples found in this thread).

3 Comments

important to only allow using static_assert_num in consteval functions, not in constexpr functions, where it might cause undefined behavior when evaluated outside a context that requires a constant expression
less risky might be calling a non-constexpr function or throwing an exception (although it is possible that these will become constant expressions to some degree at some point)
FWIW, other options closer to what you'd write normally are an assert or an if statement and throwing an exception.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.