Constexpr Not Working If the Function Is Declared Inside Class Scope

constexpr not working if the function is declared inside class scope

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.

Is the initializer of a constexpr variable at class scope allowed to reference the variable?

You aren't missing anything. This is GCC bug 99059, reported in GCC 11.

Your case applies too, since just like static inline, a constexpr variable must be initialized at the point of declaration. The same lookup related bug would affect C++14 code as well.

function scale was previously not declared constexpr

Your class Point cannot be returned by constexpr scale as it doesn't have any constexpr constructor.

So it should be:

struct Point {
public:
double x;
double y;
constexpr Point(double x, double y) : x(x), y(y){}
};

Demo

How to declare a compile-time constant scope to a class within a local scope

No, static constexpr members are banned from local classes. Probably because it wasn't free for compilers to implement it, unlike local classes. (Where is its storage declared? When is it initialized? Etc. All could be answered, but getting those answers right is a cost).

 static constexpr int NONE(){ return std::numeric_limits<int>::max(); }

this, however, works.

Constexpr doesn't get evaluated when computed using const variable outside function

The problem is that since Templates are evaluated at compile time, their arguments cannot be anything that the compiler can't "predict". In your first code the member variables MAX_NUM and MAX_SIZE are const values, meaning they cannot be changed after an instance of the class Solution is made and they are initialized. But for each instance of Solution they can still be initialized with different, unpredictable values in a constructor. The default value that you set them equal to (respectively 100 and 200) are only used if they aren't initialized during creation of an instance. Take a look at the code below:

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

class A
{
private:
const int m_foo = 1;
public:
A() {}
A(int num) : m_foo(num) {}
int foo() { return m_foo; }
};

int main()
{
A a1; //a1.m_foo initialized with default value
cout << "Enter desired m_foo for a2: ";
int foo;
cin >> foo;
A a2(foo); //a2.m_foo initialized with user input
cout << "m_foo for a1: " << a1.foo() << endl
<< "m_foo for a2: " << a2.foo();
return 0;
}

As you can see the const member variable called m_foo can be any value entered by the user.

However, when defining a const variable inside the scope of a function, that value cannot be changed and is therefore qualified as a template argument, i.e. it is similar to a constexpr.

Scope of variables declared inside `if constexpr` blocks

Your program is ill-formed because each n is restricted to the scope of the single statement declaring it.

C++17 draft N4659 [stmt.select]/1 says:

The substatement in a selection-statement (each substatement, in the else form of the if statement) implicitly defines a block scope ([basic.scope]). If the substatement in a selection-statement is a single statement and not a compound-statement, it is as if it was rewritten to be a compound statement containing the original substatement. [ Example:

if (x)
int i;

can be equivalently rewritten as

if (x) {
int i;
}

Thus after the if statement, i is no longer in scope. - end example ]

This rule applies to all for, while, switch, and if statements - whether or not the constexpr keyword is used with if.

Partially specialized template static constexpr in template class

GCC and MSVC are wrong in rejecting the code as the program is well-formed.

B is a constant expression and can be used as an initializer when initializing C during its partial specialization. This is a msvc bug reported here as:

MSVC rejects valid code when using constexpr static data member as initializer.


Moreover, we are allowed to provide a partial specialization for C(as you did). This is a gcc bug reported as:

GCC rejects valid code involving partial specialization of variable template.



Related Topics



Leave a reply



Submit