Constexpr - strange compiler behavior (C++14)

Constexpr - strange compiler behavior (C++14)

During one of my training that I provided for another edition of Nokia Academy, my attendees spotted very strange behavior of compiler when compiling constexpr functions. From the C++14 standard we know that every function can be marked as constexpr, unless it:

  • uses static or thread_local variables,
  • uses variable declarations without initializations,
  • is virtual,
  • calls non-constexpr functions,
  • uses non-literal types (values unknown during compilation),
  • uses ASM code block,
  • has try-catch blocks or throws exceptions

Take a look at below code:

#include <iostream>
using namespace std;

class Shape
{
public:
virtual ~Shape() {} virtual double getArea() const = 0;
virtual double getPerimeter() const = 0;
virtual void print() const = 0;
};
bool sortByArea(Shape* first, Shape* second)
{
if(first == NULL || second == NULL)
{
return false;
}
return (first->getArea() < second->getArea());
}
constexpr bool perimeterBiggerThan20(Shape* s)
{
if(s)
{
return (s->getPerimeter() > 20);
}
return false;
}
int main() {
// your code goes here
return 0;
}

And tell me why this code compiles? Function perimeterBiggerThan20 is marked as constexpr, but it uses virtual function inside. It's interesting because function sortByArea cannot be marked constexpr, because the compiler tells me: 

In function ‘constexpr bool sortByArea(Shape*, Shape*)’: prog.cpp:21:1: error: expression ‘Shape::getArea’ is not a constant-expression

But when I change perimererBiggerThan20 to do exactly the same thing - by just nagating the condition:

constexpr bool perimeterBiggerThan20(Shape* s)
{
if(!s)
{
return false;
}
return (s->getPerimeter() > 20);
}

It turns out that this code doesn't compile:

In function ‘constexpr bool perimeterBiggerThan20(Shape*)’:
prog.cpp:30:1: error: expression ‘Shape::getPerimeter’ is not a constant-expression


Don't you think that it's really strange? I assume that compiler is making some optimizations underneath. But for me, according to C++14 standard, it shouln't compile in any of the above forms.
I tried to compile it with several versions of g++ from 4.9 to 6.3 and the result is always the same. You can play around with this code on ideone.com

No feedback yet
Leave a comment

Your email address will not be revealed on this site.
(For my next comment on this site)
(Allow users to contact me through a message form -- Your email will not be revealed!)