2

Consider this code that static asserts false inside an if constexpr (false) statement.

#include <iostream>

template<typename T>
struct False {
    static constexpr bool value = false;
};

template<typename T>
struct Foo {
    void foo() {
        if constexpr (false) {
            static_assert(False<T>::value);
        }
        std::cout
            << "Static assert expression was: "
            << False<T>::value
            << std::endl;
    }
};

int main() {
    Foo<int> foo;
    foo.foo();
}

On both GCC 12.2 and LLVM 15.0.0, this code compiles and prints:

Static assert expression was: 0

With even minor changes, this code does not compile. Changing static_assert(False<T>::value); to static_assert(False<int>::value); or removing the if constexpr (false) check or changing it to if constexpr (true), I get "static assertion failed" as expected.

Is my above code legal? My understanding was that static_assert(...evaluates to false) is ill-formed, but the code compiles.

jcarpenter2
  • 5,312
  • 4
  • 22
  • 49
  • 4
    IIRC - `if constexpr (false)` inside a template is allowed to contain ill-formed code. – Richard Critten Sep 26 '22 at 23:54
  • 1
    Found it _"...The discarded statement can odr-use a variable that is not defined:..."_ https://en.cppreference.com/w/cpp/language/if and _"...Outside a template, a discarded statement is fully checked. if constexpr is not a substitute for the #if preprocessing directive:..."_ and a few more lines of explanation and examples – Richard Critten Sep 26 '22 at 23:57
  • 1
    @DrewDormann I think you're right, I assume that when the template is instantiated the `false` branches of any `if constexpr` statements are discarded *before* static_asserts are checked. (In this code, the template itself is not invalid because some later code could in principle override `FalseT` and make the discarded branch well-formed). The answer that quotes cppreference and mentions `dependent_false::value` gives me the information I was looking for, and seems to mean my code is also well-formed. – jcarpenter2 Sep 27 '22 at 00:14
  • 2
    Thanks, that makes sense @RichardCritten. It sounds like the template itself is only ill-formed if there exists some code somewhere in it that is ill-formed for every possible instantiation (including code that is always discarded, such as in an `if constexpr (false)` branch). However, `static_assert(FalseT::value)` could be well-formed if FalseT was specialized later in the program. – jcarpenter2 Sep 27 '22 at 00:19
  • 1
    @jcarpenter2 fyi Standard Reference [\[stmt.if #2\]](https://eel.is/c++draft/stmt.if#2) _"...During the instantiation of an enclosing templated entity ([temp.pre]), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated..."_ – Richard Critten Sep 27 '22 at 00:39

0 Answers0