Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr not working if the function is declared inside class scope

Tags:

I am using g++4.8.0, which doesn't contain earlier constexpr bug. Thus below code works fine:

constexpr int size() { return 5; } int array[size()];  int main () {} 

However, if I enclose both the variable inside a class as static, then it gives compiler error:

struct X {   constexpr static int size() { return 5; }   static const int array[size()];  };  int main () {} 

Here is the error:

error: size of array ‘array’ is not an integral constant-expression

Is it forbidden to use constexpr in such a way or yet another g++ bug?

like image 245
iammilind Avatar asked May 11 '13 04:05

iammilind


People also ask

Do constexpr functions have to be defined in header?

Constexpr functions are implicitly inline, which means they are suitable to be defined in header files. Like any function in a header, the compiler is more likely to inline it than other functions.

Can a function be constexpr?

A constexpr function is a function that can be invoked within a constant expression. A constexpr function must satisfy the following conditions: It is not virtual. Its return type is a literal type.

How do I know if a function is constexpr?

The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.

Is constexpr automatically inline?

Yes ([dcl. constexpr], §7.1. 5/2 in the C++11 standard): "constexpr functions and constexpr constructors are implicitly inline (7.1.


2 Answers

Yes, it is ill-formed. Here's why:

A constexpr function needs to be defined (not just declared) before being used in a constant expression.

So for example:

constexpr int f(); // declare f constexpr int x = f(); // use f - ILLEGAL, f not defined constexpr int f() { return 5; } // define f, too late 

function definitions inside a class specifier (as well as initializers and default parameters) are essentially parsed in an order like they were defined outside the class.

So this:

struct X {   constexpr static int size() { return 5; }   static const int array[size()];  }; 

Is parsed in this order:

struct X {    constexpr inline static int size(); // function body defered    static const int array[size()];  // <--- POINT A };  constexpr inline int X::size() { return 5; } 

That is, parsing of function bodies are defered until after the class specifier.

The purpose of this deferral of function body parsing is so that function bodies can forward reference class members not yet declared at that point, and also so they can use their own class as a complete type:

struct X {     void f() { T t; /* OK */ }     typedef int T; }; 

Compared to at namespace scope:

void f() { T t; /* error, T not declared */ } typedef int T; 

At POINT A, the compiler doesn't have the definition of size() yet, so it can't call it. For compile-time performance constexpr functions need to be defined ahead of their use in the translation unit before being called during compile, otherwise the compiler would have to make a multiple passes just to "link" constant expressions for evaluation.

like image 152
Andrew Tomazos Avatar answered Nov 07 '22 21:11

Andrew Tomazos


Apparently it's not even a bug, because its status is RESOLVED INVALID, which means that the people behind GCC and that bugzilla, after reviewing the problem, don't think that this is a GCC bug.

I remind you on that page because there is also an answer for this behaviour in one of the related posts.

like image 42
user2348816 Avatar answered Nov 07 '22 20:11

user2348816