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 theif
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
_Glibcxx_Use_Cxx11_Abi, Gcc 4.8 and Abi Compatibility
Detect When Network Cable Unplugged
Changing C++ Output Without Changing the Main() Function
Clang-Omp in Xcode Under El Capitan
How to Get the Starting/Base Address of a Process in C++
Intersection of Two 'Std::Map'S
Creating and Deallocating a Qt Widget Object
Can Cython Code Be Compiled to a Dll So C++ Application Can Call It
How to Convert a Value from Host Byte Order to Little Endian
So_Rcvtime and So_Rcvtimeo Not Affecting Boost.Asio Operations
In Which Versions of the C++ Standard Does "(I+=10)+=10" Have Undefined Behaviour
Can You Really Have a Function/Method Without a Body But Just a Try/Catch Block
Subtraction of Two Nullptr Values Guaranteed to Be Zero
C++ Class Member Function Callback
What's the Difference Between a Compiler's '-O0' Option and '-Og' Option
How Does the Friend Keyword (Class/Function) Break Encapsulation in C++