I'm confused about what I read about mixing virtual and constexpr for member functions.
According to:
up to C++17 included, it should not be possible to mix constexpr and virtual (standard is quoted in above links)
Yet I designed this straightfoward example:
#include <cstddef>
struct SizedObject {
virtual size_t GetSize() const = 0;
};
struct DynSizedObject : public SizedObject {
size_t s;
size_t GetSize() const override final { return s; }
};
struct StatSizedObject : public SizedObject {
const size_t s;
constexpr size_t GetSize() const override final { return s; }
constexpr explicit StatSizedObject(const size_t i) : s(i) {}
};
int main(int argc, char** argv) {
constexpr StatSizedObject SS(42);
DynSizedObject DS;
DS.s = argc + 2;
SizedObject const * p;
if (argc > 3) {
p = &SS;
} else {
p = &DS;
}
return p->GetSize();
}
I'm designing a hierarchy of objects with a size property that can be retrieved through the GetSize member function, which I make virtual. Now one of the concrete class can be instantiated with a compile-time size, and I make its GetSize override constexpr. Then my toy example trick the compiler in not knowing, at compile-time, which object will call GetSize. In the Live I'm surprised to see that gcc accept the code. clang reject it, seemingly consistant with the standard, while msvc do as clang but also claim that the constexpr version cannot result in a constant expression, which seems incorrect to me.
Thus my understanding would be that all compiler should behave like clang (but don't): is it correct? In this case, is it a gcc "bug" that it is accepting this construct? subsidiary question: why does msvc issue the cannot result in a constant expression error?
Beyond an academic interest, my purpose is to know if I may use some compile-time optimisation technics in relation with dynamic polymorphism (up to C++17, I know that, from C++20, some designs are possible).
C++17
In C++17, the above code would be ill-formed. What you have discovered is a compiler bug in GCC. The standard is very clear on this:
- [dcl.constexpr] p3
- [class.virtual] p2
From these two sections we can conclude that
constexpr virtualfunctions are disallowed, and any function that overrides avirtualfunction also cannot beconstexpr, because it is implicitlyvirtual.GCC Diagnostics
Interestingly enough, we get no diagnostics for
GetSizebeingvirtual constexpr, even though it is a virtual function according to the standard.If we mark the function
virtualredundantly, we do get diagnostics:MSVC Diagnostics
As for:
Admittedly, this is not a very intuitive error message. It's simply what MSVC outputs for all cases where a function cannot be
constexprbecause of its signature. You get the same message when making the return type of aconstexprfunctionstd::vector<int>.In general,
constexprmeans that at least for some arguments, a function has to be able to result in a constant expression. If the function signature makes that impossible, then specifyingconstexpris wrong.C++20
C++20 lifted these restrictions on
constexpr virtualfunctions, so the above code would be well-formed.