3

In following program the constructor of polymorphic struct A tries to dynamic_cast this to a pointer of a inherited struct B. It is done twice: using normal and constant evaluations, and the result of both is printed.

#include <iostream>

struct A {
    constexpr A();
    virtual void f() {}
    bool x;
};

struct B : A {};

constexpr A::A() { 
    x = dynamic_cast<B*>(this);
}
constexpr bool b = B{}.x;

int main() {
    std::cout << B{}.x << b;
}

With normal evaluation std::cout << B{}.x everything is simple and 0 is printed, since in the constructor of A the object cannot be cast to a child class.

But with constant evaluation the compilers diverge. Only Clang prints second 0. MSVC already prints second 1 meaning that the result of dynamic_cast was not nullptr. And GCC prints vague error:

<source>:14:24:   in 'constexpr' expansion of 'B()'
<source>:9:8:   in 'constexpr' expansion of '((B*)this)->B::<anonymous>.A::A()'
<source>:14:24: error: '((&<anonymous>.B::<anonymous>) != 0)' is not a constant expression
   14 | constexpr bool b = B{}.x;

Online demo: https://godbolt.org/z/xr8rdP93a

Is the program above well defined and if yes, what shall it print?

P.S. I think it is not a duplicate of two other questions:

because the main focus here is constant evaluation, which is not covered there at all.

Fedor
  • 17,146
  • 13
  • 40
  • 131

0 Answers0